혹시나 잘 모르시는 분을 위해 부연 설명을 하자면(이러면서 스스로 공부 한 번 더 합니다) ASP.NET에서 웹 폼 모델을 사용하게 되면 (form 태그에 runat="server" 속성을 넣으면) 기본적으로 __VIEWSTATE라는 이름을 가진 input type="hidden"개체가 생성이 되죠. 이 __VIEWSTATE는 라운드 트립이 일어날 때 ASP.NET 런타임에서 유효성 검사하는 부분이 있어서 자신의 페이지에서 전송된 것이 아니면 '데이터가 유효한지 확인할 수 없습니다'라는 에러를 내뱉습니다.
이러한 모델이 자신의 폼에서 전송이 되었다는 것을 검증하는데는 유용한 방법이나, 여러가지 사용자 요구사항에 민첩하게 대처하기 힘들다는 점이 있습니다. 페이지가 바뀌어 가면서 값이 유지 되어야 하는 경우가 대표적인 예가 되겠습니다.
궁여지책으로 Server.Transfer 메소드를 이용하는 방법도 있지만, 실행중에 자식 요청으로 다른 페이지를 사용하는 것에 대한 부담감도 있고 도메인이 달라져버리게 되는 경우 사용할 수도 없습니다. (도메인이 달라질 일이 별로 없지 않느냐 생각할 수도 있지만 SSL같은 걸 사용하게 되면 좀 달라지더라구요 ^^)
그래서 참 답답하게 ASP식으로 웹 폼 모델을 사용하지 않는 방법을 사용했었는데, 어제 문뜩 어딘가의 스크립트를 보고 영감을 얻어 작성해보았습니다. 그 이름도 유명할 '__VIEWSTATE를 회피하는 방법' 휴.. 난감하네열
요지는 간단합니다. 폼을 전송하기 전에 __VIEWSTATE 개체를 찾아서 비활성화 시켜버리는 거죠. 소스를 볼까요.
ViewStateTest1.aspx
<%@ Page language="c#" Codebehind="ViewStateTest1.aspx.cs" AutoEventWireup="false" Inherits="test.ViewStateTest1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>ViewStateTest1</title>
<script language="javascript">
function FormSubmit() {
for (i = 0; (e = document.getElementsByTagName("input")[i]); i++) {
if (e.getAttribute("type").indexOf("hidden") != -1) {
if (e.getAttribute("name") == "__VIEWSTATE") {
e.disabled = true;
break;
}
}
}
document.Form1.action = "ViewStateTest2.aspx";
document.Form1.submit();
}
</script>
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
<INPUT type="button" value="Submit another page" onclick="FormSubmit()">
</form>
</body>
</HTML>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>ViewStateTest1</title>
<script language="javascript">
function FormSubmit() {
for (i = 0; (e = document.getElementsByTagName("input")[i]); i++) {
if (e.getAttribute("type").indexOf("hidden") != -1) {
if (e.getAttribute("name") == "__VIEWSTATE") {
e.disabled = true;
break;
}
}
}
document.Form1.action = "ViewStateTest2.aspx";
document.Form1.submit();
}
</script>
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
<INPUT type="button" value="Submit another page" onclick="FormSubmit()">
</form>
</body>
</HTML>
ViewStateTest2.aspx.cs
...
/// <summary>
/// ViewStateTest2에 대한 요약 설명입니다.
/// </summary>
public class ViewStateTest2 : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
string s = "";
for (int i = 0; i < Request.Form.Count; i++)
{
s += Request.Form.GetKey(i);
s += " / " + Request.Form.Get(i) + "<br>";
}
Response.Write(s);
}
}
....
/// <summary>
/// ViewStateTest2에 대한 요약 설명입니다.
/// </summary>
public class ViewStateTest2 : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
string s = "";
for (int i = 0; i < Request.Form.Count; i++)
{
s += Request.Form.GetKey(i);
s += " / " + Request.Form.Get(i) + "<br>";
}
Response.Write(s);
}
}
....
헥헥.. 수동 하이라이팅 힘들군요. bbcode라도 달던가 해야겠네요..( 'ㅁ')a
소스를 보셨으니 더욱 명쾌하겠네요. 전송할 때 스크립트 단에서 input 태그들을 찾습니다. 거기에서 type이 hidden이고 name이 __VIEWSTATE인 개체를 찾아서 비활성화를 시켜줍니다. 그리고 전송된 내용은 ViewStateTest2.aspx에 가서 읽혀지는 거죠.
실행하게 되면 다음과 같은 결과를 얻습니다.

입력하고

받습니다
저런 처리를 해주지 않는다면 - e.disabled = true;에 주석처리를 해주면 - 에러가 납니다.

이런에러죠
결론입니다.
스크립트를 응용하면, 폼 값이나 각종 개체를 조정 가능합니다. 사실 저런 생각을 시작하게 된게, 스크립트로 document의 개체를 활성화/비활성화 시키는 걸 우연찮게 보아서 입니다.
고생 좀 안하고 편하게 살았으면 좋겠네요.
게으름은 개발자의 덕목중 하나 이죠 ;)
제루 Season 2, @Tokyo
Context 사용도 귀찮으면 Request["parameter"] 형식도 가능합니다.
책에서 읽은 기억이(?)
아크몬드 // 저의 경우 게으름 하나는 확실하게 갖추고 살죠 ㅎㅎ
저는 직렬화보다는 xml로 만들어서 보내는 방법을 사용합니다. 아무래도 디버깅이 쉽거든요. 특히 서버에 올려놓고 작업할 때 편합니다. 그리고 스크립트에서 처리하기도 편하고, 물론 보안에 대해서는 추가적인 대책은 세워야 하구요.
post방식으로 안할까도 했는데....
님 정말 감솨요~~~
^__^ 행복하세요. 부자되세요~