Silverlight를 설치하려면 여기를 클릭합니다.*
Korea 대한민국변경|Microsoft 전체 사이트
MSDN
|개발자 센터
MSDN 홈 > MSDN 칼럼 > Nothin' but ASP.NET > ASP.NET ViewState에서 바이트 가져오기

ASP.NET ViewState에서 바이트 가져오기

Susan Warren
Microsoft Corporation

새로운 ASP.NET 페이지 개발자를 만나서 이야기할 때 가장 많이 듣는 질문 중 하나는 "ViewState가 도대체 무엇인가?"라는 것입니다. 외국의 식당에서 알지 못하는 음식을 웨이터가 가져다 줄 때 느끼는 그런 불안한 기대감을 그들의 음성에서 느낄 수 있을 것입니다. 음식이 마음에 들 수도 있지만 그렇지 않을 수도 있기 때문에 먹어 보고 좋아할 수 있다 하더라도 틀림없이 낯선 느낌을 받게 될 것입니다.

ViewState에 대해서도 마찬가지입니다. ASP.NET 응용 프로그램의 ViewState를 사용하면 훨씬 적은 코드로 훨씬 많은 작업을 수행할 수 있기 때문에 ViewState에서 많은 흥미로운 환경을 발견할 수 있습니다. 경우에 따라 ViewState를 사용하고 싶은 마음이 생기지 않을 수도 있습니다. 두 가지 시나리오를 모두 살펴보겠지만 우선은 ViewState가 무엇인가에 대한 질문에 대답해 보겠습니다.

대답: ViewState는 페이지의 UI 상태를 유지합니다.

웹과 ASP.NET 페이지는 모두 상태를 저장하지 않고 서버에서 양방향으로 시작, 실행, 렌더링 및 배치됩니다. 웹 개발자는 서버에 상태를 Session 상태로 저장과 같은 잘 알려진 기술을 사용하거나 페이지를 자체적으로 다시 게시하여 상태를 저장할 수 있습니다. 그림 1의 등록 양식을 예로 들어 보겠습니다.

그림 1. 게시된 양식 값 복원

여러분은 내가 요리 항목에 대해 잘못된 값을 선택했음을 알 수 있습니다. 웹상의 대부분의 양식들처럼 이 양식에서도 오류가 있는 필드 옆에 별표와 유용한 오류 메시지가 표시됩니다. 또한 다른 입력란과 드롭다운 목록에 입력한 모든 유효한 값들이 양식에 표시됩니다. 이것은 HTML 양식 요소가 HTTP 헤더의 브라우저에서 서버로 현재 값을 게시하기 때문에 부분적으로 가능합니다. ASP.NET 추적 기능을 사용하여 그림 2에서처럼 다시 게시되는 양식 값을 볼 수 있습니다.

그림 2. ASP.NET 추적에 의해 표시된 대로 HTTP 양식에 게시되는 값

ASP.NET이 릴리스되기 전에는 다중 postback을 통해 값을 양식 필드로 다시 복원하는 것은 전적으로 페이지 개발자의 책임이었습니다. 페이지 개발자가 HTTP 양식에서 값을 하나씩 선택하여 해당 필드에 공급해야 했습니다. ASP.NET에서는 이 작업이 자동으로 수행되기 때문에 많은 귀찮은 작업들과 양식 코드가 모두 제거됩니다. 그러나 이것이 ViewState는 아닙니다.

ViewState 는 ASP.NET에서 HTTP 양식의 일부로 다시 게시되지 않는 서버 컨트롤 상태 값을 추적하는 데 사용하는 메커니즘입니다. 예를 들어, Label 컨트롤에 의해 표시된 텍스트는 기본적으로 ViewState에 저장됩니다. 개발자는 페이지가 처음 로드될 때 데이터를 바인딩하거나 레이블을 프로그램 방식으로 한 번만 설정할 수 있습니다. 후속 postback에서 레이블 텍스트가 ViewState로부터 자동으로 채워집니다. 그러므로 ViewState를 사용하면 작업 및 코드의 수가 감소될 뿐만 아니라 데이터베이스를 액세스하는 횟수도 줄일 수 있습니다.

ViewState 작동 방법

실제로 ViewState에 마법과 같은 기능은 없습니다. ViewState는 ASP.NET 페이지 프레임워크에서 관리되는 숨겨진 양식 필드입니다. ASP.NET에서 페이지를 실행하면 모든 컨트롤과 페이지로부터 ViewState 값을 수집하여 인코드된 단일 문자열로 서식을 지정한 다음 숨겨진 양식 필드(특히, <input type=hidden>)의 값 특성에 할당합니다. 숨겨진 양식 필드는 클라이언트에게 보내지는 페이지의 일부이기 때문에 ViewState 값은 클라이언트의 브라우저에 일시적으로 저장됩니다. 클라이언트가 해당 페이지를 서버에 다시 게시하도록 선택하면 ViewState 문자열도 함께 게시됩니다. 위의 그림 2에서 ViewState 양식 필드와 postback 값을 실제로 볼 수 있습니다.

postback하면 ASP.NET 페이지 프레임워크에서 ViewState 문자열을 구문 분석하여 각 컨트롤과 해당 페이지의 ViewState 속성을 자동으로 채웁니다. 컨트롤은 ViewState 데이터를 사용하여 이전의 상태로 복귀됩니다.

ViewState에 대해 작지만 유용한 다음과 같은 세 가지 사항을 알아야 합니다.

  1. ViewState를 사용하려면 ASPX 페이지에 서버쪽 양식 태그(<form runat=server>)가 있어야 합니다. ViewState 정보가 들어 있는 숨겨진 필드를 서버에 다시 게시하려면 양식 필드가 필요합니다. 페이지가 서버에서 실행될 때 ASP.NET 페이지 프레임워크가 숨겨진 필드를 추가할 수 있도록 서버쪽 양식이 있어야 합니다.
  2. 페이지는 ViewState에 약 20바이트의 정보를 저장하여 postback할 때 PostBack 데이터와 ViewState 값을 올바른 컨트롤에 배포하는 데 사용합니다. 따라서 해당 페이지나 응용 프로그램에서 ViewState를 사용하지 않더라도 ViewState에 몇 바이트의 정보가 남아 있을 수 있습니다.
  3. 페이지를 다시 게시하지 않을 경우 서버쪽 <form> 태그를 생략하여 해당 페이지에서 ViewState를 제거할 수 있습니다.

ViewState에 대한 자세한 정보

ViewState는 서버 리소스를 사용하지 않고 시간 제한 없이 모든 브라우저에서 작동되기 때문에 postback을 수행하는 동안 컨트롤의 상태를 추적하는 최고의 방법입니다. 컨트롤 작성자인 경우 Maintaining State in a Control을 참조하십시오.

페이지 작성자의 경우에도 ViewState에서 동일한 혜택을 누릴 수 있습니다. 페이지에 컨트롤에 의해 저장되지 않는 UI 상태 값이 포함되어 있는 경우 Session과 Cache에 사용되는 것과 비슷한 프로그래밍 구문을 사용하여 ViewState 값을 추적할 수 있습니다.

[Visual Basic]

' ViewState에 저장
ViewState("SortOrder") = "DESC"

' ViewState로부터 읽기
Dim SortOrder As String = CStr(ViewState("SortOrder"))

[C#]

// ViewState에 저장
ViewState["SortOrder"] = "DESC";

// ViewState로부터 읽기
string sortOrder = (string)ViewState["SortOrder"];

예를 들어, 웹 페이지에 항목의 목록을 표시하고 각 사용자가 해당 목록을 다르게 정렬한다고 가정합니다. 항목의 목록은 정적이기 때문에 각 페이지는 동일한 데이터 캐시 집합에 바인딩될 수 있지만 사용자마다 UI 상태의 정렬 순서가 조금씩 다릅니다. ViewState는 이러한 유형의 값을 저장하는 훌륭한 장소입니다. 코드는 다음과 같습니다.

[Visual Basic]

<%@ Import Namespace="System.Data" %>
<HTML>
    <HEAD>
        <title>페이지 UI 상태 값에 대한 ViewState</title>
    </HEAD>
    <body>
        <form runat="server">
            <H3>
                비컨트롤 상태를 ViewState에 저장
            </H3>
            <P>
                이 예제에서는 ViewState에 데이터의 정적 목록에 대한 현재 정렬 순서를 저장합니다.<br>
                데이터를 해당 필드 순으로 정렬하려면 열 머리글의 링크를 클릭하십시오.<br>
                반대 방향으로 정렬하려면 링크를 두 번 클릭하십시오.                <br><br><br>
                <asp:datagrid id="DataGrid1" runat="server"
OnSortCommand="SortGrid" BorderStyle="None" BorderWidth="1px"
BorderColor="#CCCCCC" BackColor="White" CellPadding="5" AllowSorting="True">
                    <HeaderStyle Font-Bold="True" ForeColor="White"
BackColor="#006699">
                    </HeaderStyle>
                </asp:datagrid>
            </P>
        </form>
    </body>
</HTML>
<script runat="server">

    ' SortField 속성이 ViewState에서 추적됩니다.
    Property SortField() As String

        Get
            Dim o As Object = ViewState("SortField")
            If o Is Nothing Then
                Return String.Empty
            End If
            Return CStr(o)
        End Get

        Set(Value As String)
            If Value = SortField Then
                ' 현재 정렬 파일과 같게 정렬 방향 전환
                SortAscending = Not SortAscending
            End If
            ViewState("SortField") = Value
        End Set

    End Property

    ' SortAscending 속성이 ViewState에서 추적됩니다.
    Property SortAscending() As Boolean

        Get
            Dim o As Object = ViewState("SortAscending")
            If o Is Nothing Then
                Return True
            End If
            Return CBool(o)
        End Get

        Set(Value As Boolean)
            ViewState("SortAscending") = Value
        End Set

    End Property

    Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        If Not Page.IsPostBack Then
            BindGrid()
        End If

    End Sub

    Sub BindGrid()

        ' 데이터 가져오기
        Dim ds As New DataSet()
        ds.ReadXml(Server.MapPath("TestData.xml"))

        Dim dv As New DataView(ds.Tables(0))

        ' 정렬 필터와 방향 적용
        dv.Sort = SortField
        If Not SortAscending Then
            dv.Sort += " DESC"
        End If

        ' 눈금 바인딩
        DataGrid1.DataSource = dv
        DataGrid1.DataBind()

    End Sub

    Private Sub SortGrid(sender As Object, e As DataGridSortCommandEventArgs)
        DataGrid1.CurrentPageIndex = 0
        SortField = e.SortExpression
        BindGrid()
    End Sub

</script>

[C#]

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<HTML>
    <HEAD>
        <title>페이지 UI 상태 값에 대한 ViewState</title>
    </HEAD>
    <body>
        <form runat="server">
            <H3>
                비컨트롤 상태를 ViewState에 저장
            </H3>
            <P>
                이 예제에서는 ViewState에 데이터의 정적 목록에 대한 현재 정렬 순서를 저장합니다.<br>
                데이터를 해당 필드 순으로 정렬하려면 열 머리글의 링크를 클릭하십시오.<br>
                반대 방향으로 정렬하려면 링크를 두 번 클릭하십시오.                <br><br><br>
                <asp:datagrid id="DataGrid1" runat="server" OnSortCommand="SortGrid"
                BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
                BackColor="White" CellPadding="5" AllowSorting="True">
                    <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
                    </HeaderStyle>
                </asp:datagrid>
            </P>
        </form>
    </body>
</HTML>
<script runat="server">

    // SortField 속성이 ViewState에서 추적됩니다.
    string SortField {

        get {
            object o = ViewState["SortField"];
            if (o == null) {
                return String.Empty;
            }
            return (string)o;
        }

        set {
            if (value == SortField) {
                // 현재 정렬 파일과 같게 정렬 방향 전환
                SortAscending = !SortAscending;
            }
            ViewState["SortField"] = value;
        }
    }

    // SortAscending 속성이 ViewState에서 추적됩니다.
    bool SortAscending {

        get {
            object o = ViewState["SortAscending"];
            if (o == null) {
                return true;
            }
            return (bool)o;
        }

        set {
            ViewState["SortAscending"] = value;
        }
    }

    void Page_Load(object sender, EventArgs e) {

        if (!Page.IsPostBack) {
            BindGrid();
        }
    }

    void BindGrid() {

        // 데이터 가져오기
        DataSet ds = new DataSet();
        ds.ReadXml(Server.MapPath("TestData.xml"));

        DataView dv = new DataView(ds.Tables[0]);

        // 정렬 필터와 방향 적용
        dv.Sort = SortField;
        if (!SortAscending) {
            dv.Sort += " DESC";
        }

        // 눈금 바인딩
        DataGrid1.DataSource = dv;
        DataGrid1.DataBind();
   }

   void SortGrid(object sender, DataGridSortCommandEventArgs e) {

        DataGrid1.CurrentPageIndex = 0;
        SortField = e.SortExpression;
        BindGrid();
    }

</script>

위의 코드 섹션 모두에서 참조되는 testdata.xml의 코드는 다음과 같습니다.

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <Table>
    <pub_id>0736</pub_id>
    <pub_name>New Moon Books</pub_name>
    <city>Boston</city>
    <state>MA</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>0877</pub_id>
    <pub_name>Binnet &amp; Hardley</pub_name>
    <city>Washington</city>
    <state>DC</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>1389</pub_id>
    <pub_name>Algodata Infosystems</pub_name>
    <city>Berkeley</city>
    <state>CA</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>1622</pub_id>
    <pub_name>Five Lakes Publishing</pub_name>
    <city>Chicago</city>
    <state>IL</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>1756</pub_id>
    <pub_name>Ramona Publishers</pub_name>
    <city>Dallas</city>
    <state>TX</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>9901</pub_id>
    <pub_name>GGG&amp;G</pub_name>
    <city>M?chen</city>
    <country>Germany</country>
  </Table>
  <Table>
    <pub_id>9952</pub_id>
    <pub_name>Scootney Books</pub_name>
    <city>New York</city>
    <state>NY</state>
    <country>USA</country>
  </Table>
  <Table>
    <pub_id>9999</pub_id>
    <pub_name>Lucerne Publishing</pub_name>
    <city>Paris</city>
    <country>France</country>
  </Table>
</NewDataSet>

세션 상태 또는 ViewState?

ViewState에 상태 값을 보관하는 것이 좋지 않은 경우도 있습니다. 이 경우 Session 상태가 가장 일반적으로 사용되며 다음의 경우에 가장 알맞습니다.

  • 대량의 데이터. ViewState는 브라우저에 보내지는 페이지의 크기(HTML 페이로드)와 다시 게시되는 양식의 크기를 모두 증가시키기 때문에 대량의 데이터를 저장할 경우에는 적합하지 않습니다.
  • UI에 아직 표시되지 않은 데이터 보안. ViewState 데이터는 인코드되고 선택적으로 암호화되지만 데이터는 클라이언트에 전송되는 한 안전하지 않습니다. 따라서 Session 상태가 더 보안적인 옵션입니다. 데이터베이스에 데이터를 저장하면 추가적인 데이터베이스 자격 증명으로 인해 훨씬 보안적입니다. SSL을 추가하여 링크 보안을 강화할 수 있습니다. UI에 개인 데이터를 표시한 경우 링크 자체의 보안에 이미 익숙해져 있을 수 있습니다. 이 경우 ViewState에 동일한 값을 입력하는 만큼의 보안이 제공됩니다.
  • ViewState로 즉시 일련화되지 않는 개체(예: DataSet). ViewState serializer는 아래 나열된 소량의 일반 개체 유형 집합에 맞게 최적화됩니다. 일련화될 수 있는 다른 유형은 ViewState에서 지속될 수 있지만 속도가 느려지고 매우 큰 ViewState 흔적을 생성합니다.
  Session 상태 ViewState
서버 리소스를 보관합니까? 아니오
시간 제한이 있습니까? 예 – 20분 후(기본값) 아니오
모든 .NET 형식을 저장합니까? 아니오, 문자열, 정수, 부울, 배열, ArrayList, 해시 테이블, 사용자 지정 TypeConverter 등의 형식만 지원합니다.
"HTML 페이로드"가 증가됩니까? 아니오

ViewState로 최상의 성능 내기

ViewState로 이동할 때 각 개체를 일련화한 다음 다시 게시할 때 해제해야 하기 때문에 ViewState를 사용할 경우 성능에 따른 비용을 부담해야 합니다. 그러나 간단한 지침에 따라 ViewState 비용을 제어한다면 성능에 미치는 영향이 그리 크지 않습니다.

  • 필요하지 않을 경우 ViewState를 해제합니다. 이 문제에 대해서는 다음 섹션 ViewState에 대한 기타 정보에서 자세히 다룹니다.
  • 최적화된 ViewState serializer를 사용합니다. 위에 나열된 유형들은 속도가 매우 빠르고 최적화되어 소량의 ViewState 흔적만 생성하는 특수 serializer를 갖습니다. 위에 나열되지 않은 유형을 일련화하려면 사용자 지정 TypeConverter를 만들어 성능을 크게 향상시킬 수 있습니다.
  • 가장 적은 수의 개체를 사용하고 가능하면 ViewState에 입력하는 개체의 수를 줄입니다. 예를 들어, 배열의 길이와 같은 수의 개체를 갖는 이름/값의 2차원 문자열 배열 대신 두 개의 문자열 배열(두 개체만)을 사용합니다. 그러나 ViewState에 저장하기 전에 알려진 두 유형 사이를 변환하면 기본적으로 변환 비용이 두 배로 들기 때문에 성능상의 혜택이 없습니다.

ViewState에 대한 기타 정보

ViewState는 기본적으로 사용되며 ViewState에 저장되는 내용은 페이지 개발자가 아니라 각 컨트롤에서 결정합니다. 이 정보는 사용자의 응용 프로그램에는 맞지 않을 수도 있습니다. ViewState는 해가 되지는 않더라도 브라우저에 보내지는 페이지의 크기를 상당히 증가시킬 수 있습니다. 특별히 ViewState의 크기가 매우 커서 ViewState를 사용하지 않을 경우 ViewState를 종료하는 것이 좋습니다.

ViewState를 컨트롤, 페이지 또는 응용 프로그램 단위로 종료할 수 있습니다. 다음과 같은 경우 ViewState가 필요하지 않습니다.

페이지 컨트롤
  • 페이지는 자체적으로 다시 게시되지 않습니다.
  • 컨트롤의 이벤트를 처리하지 않습니다.
  • 컨트롤에 동적 또는 데이터 바운드 속성 값이 없거나 요청이 있을 때마다 코드에 설정됩니다.

DataGrid 컨트롤이 ViewState를 가장 많이 사용합니다. 기본적으로 모눈에 표시되는 모든 데이터는 ViewState에도 저장되므로 데이터를 불러오는 데 비용이 많이 드는 작업(예: 복잡한 검색)을 수행해야 하는 경우에 매우 유용합니다. 그러나 이 동작은 DataGrid를 불필요한 ViewState에 대한 제1의 주의 대상으로 만듭니다.

예를 들어, 위의 조건을 충족하는 간단한 페이지는 다음과 같습니다. 페이지는 자체적으로 다시 게시되지 않기 때문에 ViewState가 필요하지 않습니다.

그림 3. DataGrid1을 갖는 간단한 페이지 LessViewState.aspx

<%@ Import Namespace="System.Data" %>
<html>
    <body>
        <form runat="server">
            <asp:DataGrid runat="server" />
        </form>
    </body>
</html>
<script runat="server">

    Private Sub Page_Load(sender As Object, e As EventArgs)

        Dim ds as New DataSet()
        ds.ReadXml(Server.MapPath("TestData.xml"))

        DataGrid1.DataSource = ds
        DataGrid1.DataBind()

    End Sub

</script>

ViewState를 사용하면 이 작은 모눈이 페이지의 HTML 페이로드에 3000바이트 이상을 제공합니다. 아래 코드에 표시된 것처럼 브라우저에 보내지는 페이지의 원본을 표시하거나 ASP.NET Tracing 을 사용하여 다음 내용을 볼 수 있습니다.

<HTML>
    <HEAD>
        <title>"HTML 페이로드" 페이지 줄이기</title>
    </HEAD>
    <body>
    <form name="_ctl0" method="post" action="lessviewstate.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwxNTgzOTU2ODA7dDw7bDxpPDE+Oz47bDx0PDtsPGk8MT47PjtsPHQ8QDA8cDxw
PGw8UGFnZUNvdW50O18hSXRlbUNvdW50O18hRGF0YVNvdXJjZUl0ZW1Db3VudDtEYXRhS2V
5czs+O2w8aTwxPjtpPDg+O2k8OD47bDw+Oz4+Oz47Ozs7Ozs7OztAMDxAMDxwPGw8SGVhZG
VyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHB1Yl9pZDtwd
WJfaWQ7cHViX2lkO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ7
U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHB1Yl9uYW1lO3B1Yl9uYW1lO3B1Yl9uYW1
lO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3
Npb247UmVhZE9ubHk7PjtsPGNpdHk7Y2l0eTtjaXR5O288Zj47Pj47Ozs7PjtAMDxwPGw8S
GVhZGVyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHN0YXRl
O3N0YXRlO3N0YXRlO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ
7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPGNvdW50cnk7Y291bnRyeTtjb3VudHJ5O2
88Zj47Pj47Ozs7Pjs+Oz47bDxpPDA+Oz47bDx0PDtsPGk8MT47aTwyPjtpPDM+O2k8ND47a
Tw1PjtpPDY+O2k8Nz47aTw4Pjs+O2w8dDw7bDxpPDA+O2k8MT47aTwyPjtpPDM+O2k8ND47
PjtsPHQ8cDxwPGw8VGV4dDs+O2w8MDczNjs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8TmV
3IE1vb24gQm9va3M7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEJvc3Rvbjs+Pjs+Ozs+O3
Q8cDxwPGw8VGV4dDs+O2w8TUE7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPFVTQTs+Pjs+O
zs+Oz4+O3Q8O2w8aTwwPjtpPDE+O2k8Mj47aTwzPjtpPDQ+Oz47bDx0PHA8cDxsPFRleHQ7
PjtsPDA4Nzc7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEJpbm5ldCAmIEhhcmRsZXk7Pj4
7Pjs7Pjt0PH_u56 ?cDxsPFRleHQ7PjtsPFdhc2hpbmd0b247Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPERDOz
4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxP
jtpPDI+O2k8Mz47aTw0Pjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwxMzg5Oz4+Oz47Oz47dDxw
PHA8bDxUZXh0Oz47bDxBbGdvZGF0YSBJbmZvc3lzdGVtczs+Pjs+Ozs+O3Q8cDxwPGw8VGV
4dDs+O2w8QmVya2VsZXk7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPENBOz4+Oz47Oz47dD
xwPHA8bDxUZXh0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxPjtpPDI+O2k8M
z47aTw0Pjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwxNjIyOz4+Oz47Oz47dDxwPHA8bDxUZXh0
Oz47bDxGaXZlIExha2VzIFB1Ymxpc2hpbmc7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEN
oaWNhZ287Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPElMOz4+Oz47Oz47dDxwPHA8bDxUZX
h0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxPjtpPDI+O2k8Mz47aTw0Pjs+O
2w8dDxwPHA8bDxUZXh0Oz47bDwxNzU2Oz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxSYW1v
bmEgUHVibGlzaGVyczs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8RGFsbGFzOz4+Oz47Oz4
7dDxwPHA8bDxUZXh0Oz47bDxUWDs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8VVNBOz4+Oz
47Oz47Pj47dDw7bDxpPDA+O2k8MT47aTwyPjtpPDM+O2k8ND47PjtsPHQ8cDxwPGw8VGV4d
Ds+O2w8OTkwMTs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8R0dHJkc7Pj47Pjs7Pjt0PHA8
cDxsPFRleHQ7PjtsPE3DvG5jaGVuOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDwmbmJzcFw
7Oz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxHZXJtYW55Oz4+Oz47Oz47Pj47dDw7bDxpPD
A+O2k8MT47aTwyPjtpPDM+O2k8ND47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8OTk1Mjs+Pjs+O
zs+O3Q8cDxwPGw8VGV4dDs+O2w8U2Nvb3RuZXkgQm9va3M7Pj47Pjs7Pjt0PHA8cDxsPFRl
eHQ7PjtsPE5ldyBZb3JrOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxOWTs+Pjs+Ozs+O3Q
8cDxwPGw8VGV4dDs+O2w8VVNBOz4+Oz47Oz47Pj47dDw7bDxpPDA+O2k8MT47aTwyPjtpPD
M+O2k8ND47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8OTk5OTs+Pjs+Ozs+O3Q8cDxwPGw8VGV4d
Ds+O2w8THVjZXJuZSBQdWJsaXNoaW5nOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxQYXJp
czs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8Jm5ic3BcOzs+Pjs+Ozs+O3Q8cDxwPGw8VGV
4dDs+O2w8RnJhbmNlOz4+Oz47Oz47Pj47Pj47Pj47Pj47Pj47Pg==" />

그러나 모눈에 대해 ViewState를 해제하기만 하면 동일한 페이지에 대한 페이로드 크기가 극적으로 줄어듭니다.

<HTML>
    <HEAD>
        <title>"HTML 페이로드" 페이지 줄이기</title>
    </HEAD>
    <body>
    <form name="_ctl0" method="post" action="lessviewstate.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNTgzOTU2ODA7Oz4=" />

Visual Basic과 C#으로 된 전체 LessViewState 코드는 다음과 같습니다.

[Visual Basic]

<%@ Import Namespace="System.Data" %>
<html>
    <HEAD>
        <title>"HTML 페이로드" 페이지 줄이기</title>
    </HEAD>
    <body>
        <form runat="server">
            <H3>
                ViewState를 비활성화하여 "HTML 페이로드" 페이지 줄이기
            </H3>
            <P>
                <asp:datagrid id="DataGrid1" runat="server" EnableViewState="false"
                BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
                BackColor="White" CellPadding="5">
                    <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
                    </HeaderStyle>
                </asp:datagrid>
            </P>
        </form>
    </body>
</html><script runat="server">

    Private Sub Page_Load(sender As Object, e As EventArgs)

        Dim ds as New DataSet()
        ds.ReadXml(Server.MapPath("TestData.xml"))

        DataGrid1.DataSource = ds
        DataGrid1.DataBind()

    End Sub

</script>

[C#]

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<html>
    <HEAD>
        <title>"HTML 페이로드" 페이지 줄이기</title>
    </HEAD>
    <body>
        <form runat="server">
            <H3>
                ViewState를 비활성화하여 "HTML 페이로드" 페이지 줄이기
            </H3>
            <P>
                <asp:datagrid id="DataGrid1" runat="server" EnableViewState="false"
                BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
                BackColor="White" CellPadding="5">
                    <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
                    </HeaderStyle>
                </asp:datagrid>
            </P>
        </form>
    </body>
</html>
<script runat="server">

    void Page_Load(object sender, EventArgs e) {

        DataSet ds = new DataSet();
        ds.ReadXml(Server.MapPath("TestData.xml"));

        DataGrid1.DataSource = ds;
        DataGrid1.DataBind();
    }

</script>

ViewState 비활성화

위 예제에서는 모눈의 EnableViewState 속성을 false로 설정하여 모눈에 대해 ViewState를 비활성화했습니다. 다음과 같이 단일 컨트롤, 전체 페이지 또는 전체 응용 프로그램에 대해 ViewState를 비활성화할 수 있습니다.

컨트롤 단위(태그에서) <asp:datagrid EnableViewState="false" ?/>
페이지 단위(지시문에서) <%@ Page EnableViewState="False" ?%>
응용 프로그램 단위(web.config에서) <Pages EnableViewState="false" ?/>

ViewState 보안 강화

ViewState의 서식이 일반 텍스트로 지정되지 않기 때문에 ViewState가 암호화되는 것으로 간주하는 경우가 있지만 그렇지 않습니다. ViewState는 단순히 64 기수로 인코드되므로 응용 프로그램에서 사용되는 응답/요청 인코딩에 관계 없이 이동하는 동안 변경되지 않습니다.

응용 프로그램에 추가할 수 있는 ViewState의 두 가지 보안 수준은 다음과 같습니다.

  • 무단 변경 방지
  • 암호화

ViewState 보안은 ASP.NET 페이지를 처리 및 렌더링하는 데 필요한 시간에 직접적인 영향을 미칩니다. 간단히 말해서 보안 수준이 높을수록 속도가 느려지므로 필요하지 않을 경우 ViewState에 보안을 추가하지 마십시오.

무단 변경 방지

해시 코드는 ViewState 필드에 있는 실제 데이터를 보안하지 않지만 다른 사용자가 ViewState를 무단으로 변경하여 응용 프로그램을 불법으로 사용할 가능성을 크게 줄입니다. 즉, 사용자가 응용 프로그램에 입력하지 못하도록 값을 다시 게시합니다.

EnableViewStateMAC 특성을 다음과 같이 설정하여 ViewState 필드에 해시 코드를 추가하도록 ASP.NET에 명령할 수 있습니다.

<%@Page EnableViewStateMAC=true %>

EnableViewStateMAC은 페이지 수준 또는 응용 프로그램 수준으로 설정될 수 있습니다. postback하면 ASP.NET은 ViewState 데이터에 대한 해시 코드를 생성하여 게시된 값의 해시 코드와 비교합니다. 두 해시 코드가 일치하지 않으면 ViewState 데이터가 삭제되고 컨트롤이 원래의 설정으로 변환됩니다.

기본적으로 ASP.NET은 SHA1 알고리즘을 사용하여 ViewState 해시 코드를 생성합니다. machine.config 파일에서 <machineKey>를 다음과 같이 설정하여 MD5 알고리즘을 선택할 수도 있습니다.

<machineKey validation="MD5" />

암호화

암호화를 사용하여 ViewState 필드에 있는 실제 데이터 값을 보호할 수 있습니다. 먼저 위에서처럼 EnableViewStatMAC="true"로 설정한 다음 machineKey 유효성 유형을 3DES로 설정해야 합니다. 이렇게 하면 Triple DES 대칭 암호화 알고리즘을 사용하여 ViewState 값을 암호화하도록 ASP.NET에 명령합니다.

<machineKey validation="3DES" />

웹 그룹에서 ViewState 보안

기본적으로 ASP.NET은 임의의 유효성 키를 만들어 각 서버의 LSA(Local Security Authority)에 저장합니다. 다른 서버에 만들어진 ViewState 필드의 유효성을 검사하려면 두 서버의 validationKey를 동일한 값으로 설정해야 합니다. 웹 그룹 구성으로 실행되는 응용 프로그램에 대해 위에 나열된 수단을 사용하여 ViewState를 보안할 경우 모든 서버에 대해 단일의 공유 유효성 키를 제공해야 합니다.

유효성 키는 "암호로 보안"되는 20 - 64 바이트의 임의의 문자열로 40자에서 128자까지의 16진수로 표시됩니다. 길이가 길수록 보안 수준이 높으므로 128자 키(시스템에서 지원할 경우)를 사용하는 것이 좋습니다. 예를 들면 다음과 같습니다.

<machineKey validation="SHA1" validationKey="
F3690E7A3143C185AB1089616A8B4D81FD55DD7A69EEAA3B32A6AE813ECEECD28DEA66A
23BEE42193729BD48595EBAFE2C2E765BE77E006330BC3B1392D7C73F" />

다음 GenerateCryptoKey.aspx 샘플에서 설명하는 것처럼 System.Security.Cryptography 네임스페이스에는 이 문자열을 생성하는 데 사용할 수 있는 RNGCryptoServiceProvider 클래스가 포함되어 있습니다.

<%@ Page Language="c#" %>
<%@ Import Namespace="System.Security.Cryptography" %>
<HTML>
    <body>
        <form runat="server">
        <H3>임의의 암호화 키 생성</H3>
        <P>
            <asp:RadioButtonList id="RadioButtonList1"
            runat="server" RepeatDirection="Horizontal">
                <asp:ListItem Value="40">40-byte</asp:ListItem>
                <asp:ListItem Value="128" Selected="True">128-byte</asp:ListItem>
            </asp:RadioButtonList>&nbsp;
            <asp:Button id="Button1" runat="server" onclick="GenerateKey"
            Text="키 생성">
            </asp:Button></P>
        <P>
            <asp:TextBox id="TextBox1" runat="server" TextMode="MultiLine"
            Rows="10" Columns="70" BackColor="#EEEEEE" EnableViewState="False">
            생성된 결과를 복사하여 붙여넣기</asp:TextBox></P>
        </form>
    </body>
</HTML>


<script runat=server>

   void GenerateKey(object sender, System.EventArgs e)
   {
       int keylength = Int32.Parse(RadioButtonList1.SelectedItem.Value);

      // 여기에 사용자 코드를 배치하여 페이지를 초기화합니다.
        byte[] buff = new Byte[keylength/2];

        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        // 이제 배열이 암호화 수준이 높은 임의의 바이트로 채워집니다.
        rng.GetBytes(buff);

        StringBuilder sb = new StringBuilder(keylength);
        int i;
        for (i = 0; i < buff.Length; i++) {
            sb.Append(String.Format("{0:X2}",buff[i]));
        }

        // 사용자가 복사할 수 있도록 textbox에 붙여넣습니다.
        TextBox1.Text = sb.ToString();
    }

</script>

요약

ASP.NET의 ViewState는 개발자가 UI 상태를 사용자 단위로 추적하는 데 사용할 수 있는 새로운 유형의 상태 서비스입니다. 마술과 같은 것이 아니라 숨겨진 양식 필드에서 상태를 주고 받는 이전의 웹 프로그래밍 기술을 사용하여 페이지 처리 프레임워크에 맞게 개발한 것입니다. 그러나 결과는 매우 우수하여 웹 기반 양식에서 작성 및 유지할 코드 수를 상당히 줄여줍니다.

항상 필요한 것은 아니지만 필요할 경우 ViewState는 페이지 개발자들에게 ASP.NET이 제공하는 다채로운 새로운 기능들을 제공합니다.

Susan Warren은 .NET Framework 팀의 ASP.NET 프로그램 관리자입니다.




최종 수정일: 2002년 2월 6일
Top of Page Top of Page


Microsoft