<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    注銷

    注銷

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      112 隨筆 :: 7 文章 :: 18 評論 :: 0 Trackbacks

    ASP.NET ViewState 初探


    Susan Warren
    Microsoft Corporation
    2001 年 11 月 27 日

    與剛接觸 ASP.NET 頁面的開發(fā)人員交談時,他們通常向我提出的第一個問題就是:“那個 ViewState 到底是什么?”他們的語氣中流露出的那種感覺,就象我來到一家異國情調的餐館,侍者端上一道我從未見過的菜肴時的那種感覺 - 既疑惑不解,又充滿好奇。但肯定有人認為它不錯,否則就不會提供了。所以,我會先嘗一嘗,或許會喜歡上它,盡管它看上去的確很古怪!

    對于 ViewState 也是如此,但是如果適應了它的風格,您會發(fā)現在許多情況下,您將樂于在自己的 ASP.NET 應用程序中使用 ViewState,因為它可以幫助您使用更少的代碼完成更多的工作。但是,有時也會對 ViewState 完全棄之不用。下面我們就這兩種情況分別進行闡述,不過,讓我們先回答什么是 ViewState 這個問題。

    答案:ViewState 用于維護頁面的 UI 狀態(tài)

    Web 是沒有狀態(tài)的,ASP.NET 頁面也沒有狀態(tài),它們在到服務器的每個往返過程中被實例化、執(zhí)行、呈現和處理。作為 Web 開發(fā)人員,您可以使用眾所周知的技術(如以會話狀態(tài)將狀態(tài)存儲在服務器上,或將頁面回傳到自身)來添加狀態(tài)。下面我們以圖 1 中的注冊窗體為例進行論述。

    圖 1:恢復回傳的窗體值

    從上圖中可以看出,我為便餐選擇了一個無效的值。此窗體與 Web 上的多數窗體一樣友好,它在出現錯誤的字段旁邊顯示一條有用的錯誤消息和一個星號。而且,窗體中還顯示了我在其他文本框和下拉列表中輸入的所有有效值。這在某種程度上是可能的,因為 HTML 窗體元素會在 HTTP 標頭中將其當前值從瀏覽器發(fā)送到服務器。您可以使用 ASP.NET 跟蹤來查看回傳的窗體值,如圖 2 所示。

    圖 2:HTTP 窗體中回傳的值(通過 ASP.NET 跟蹤顯示)

    在 ASP.NET 之前,通過多次回傳將值恢復到窗體字段中完全是頁面開發(fā)人員的責任,他們將不得不從 HTTP 窗體中逐個拾取回傳值,然后再將其推回字段中。幸運的是,現在 ASP.NET 可以自動完成這項任務,從而為開發(fā)人員免除了一項令人厭煩的工作,同時也無需再為窗體編寫大量的代碼。但這并不是 ViewState。

    ViewState(英文)是一種機制,ASP.NET 使用這種機制來跟蹤服務器控件狀態(tài)值,否則這些值將不作為 HTTP 窗體的一部分而回傳。例如,由 Label 控件顯示的文本默認情況下就保存在 ViewState 中。作為開發(fā)人員,您可以綁定數據,或在首次加載該頁面時僅對 Label 編程設置一次,在后續(xù)的回傳中,該標簽文本將自動從 ViewState 中重新填充。因此,除了可以減少繁瑣的工作和代碼外,ViewState 通常還可以減少數據庫的往返次數。

    ViewState 的工作原理

    ViewState 確實沒有什么神秘之處,它是由 ASP.NET 頁面框架管理的一個隱藏的窗體字段。當 ASP.NET 執(zhí)行某個頁面時,該頁面上的 ViewState 值和所有控件將被收集并格式化成一個編碼字符串,然后被分配給隱藏窗體字段的值屬性(即 <input type=hidden>)。由于隱藏窗體字段是發(fā)送到客戶端的頁面的一部分,所以 ViewState 值被臨時存儲在客戶端的瀏覽器中。如果客戶端選擇將該頁面回傳給服務器,則 ViewState 字符串也將被回傳。在上面的圖 2 中可以看到 ViewState 窗體字段及其回傳的值。

    回傳后,ASP.NET 頁面框架將解析 ViewState 字符串,并為該頁面和各個控件填充 ViewState 屬性。然后,控件再使用 ViewState 數據將自己重新恢復為以前的狀態(tài)。

    關于 ViewState 還有三個值得注意的小問題。

    1. 如果要使用 ViewState,則在 ASPX 頁面中必須有一個服務器端窗體標記 (<form runat=server>)。窗體字段是必需的,這樣包含 ViewState 信息的隱藏字段才能回傳給服務器。而且,該窗體還必須是服務器端的窗體,這樣在服務器上執(zhí)行該頁面時,ASP.NET 頁面框架才能添加隱藏的字段。
    2. 頁面本身將 20 字節(jié)左右的信息保存在 ViewState 中,用于在回傳時將 PostBack 數據和 ViewState 值分發(fā)給正確的控件。因此,即使該頁面或應用程序禁用了 ViewState,仍可以在 ViewState 中看到少量的剩余字節(jié)。
    3. 在頁面不回傳的情況下,可以通過省略服務器端的 <form> 標記來去除頁面中的 ViewState。

    充分利用 ViewState

    ViewState 為跨回傳跟蹤控件的狀態(tài)提供了一條神奇的途徑,因為它不使用服務器資源、不會超時,并且適用于任何瀏覽器。如果您要編寫控件,那么肯定需要了解如何在控件中維護狀態(tài)(英文)。

    開發(fā)人員在編寫頁面時同樣可以按照幾乎相同的方式來利用 ViewState,只是有時頁面會包含不由控件存儲的 UI 狀態(tài)值。您可以跟蹤 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"];
    

    請看下面的示例:要在 Web 頁上顯示一個項目列表,而每個用戶需要不同的列表排序。項目列表是靜態(tài)的,因此可以將這些頁面綁定到相同的緩存數據集,而排序順序只是用戶特定的 UI 狀態(tài)的一小部分。ViewState 非常適合于存儲這種類型的值。代碼如下:

    [Visual Basic]

    <%@ Import Namespace="System.Data" %>
    <HTML>
        <HEAD>
            <title>用于頁面 UI 狀態(tài)值的 ViewState/title>
        </HEAD>
        <body>
            <form runat="server">
                <H3>
                    在 ViewState 中存儲非控件狀態(tài)
                </H3>
                <P>
                    此示例將一列靜態(tài)數據的當前排序順序存儲在 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">
    
        ' 在 ViewState 中跟蹤 SortField 屬性
        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
    
        ' 在 ViewState 中跟蹤 SortAscending 屬性
        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 狀態(tài)值的 ViewState</title>
        </HEAD>
        <body>
            <form runat="server">
                <H3>
                    在 ViewState 中存儲非控件狀態(tài)
                </H3>
                <P>
                    此示例將一列靜態(tài)數據的當前排序順序存儲在 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">
    
        // 在 ViewState 中跟蹤 SortField 屬性
        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;
            }
        }
    
        // 在 ViewState 中跟蹤 SortAscending 屬性
        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>Muenchen</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>
    

    選擇會話狀態(tài)還是 ViewState?

    在某些情況下,將狀態(tài)值保存在 ViewState 中并不是最佳選擇,最常用的替代方法就是會話狀態(tài),它通常更適用于:

    • 大量的數據。由于 ViewState 增加了發(fā)送到瀏覽器的頁面的大小(HTML 有效負載),同時也增加了回傳的窗體的大小,因此不適合存儲大量數據。
    • 未在 UI 中顯示的安全數據。盡管 ViewState 數據已被編碼,并且可以選擇對其進行加密,但始終不將數據發(fā)送到客戶端才是最安全的。因此,會話是更安全的選擇。(由于數據庫需要額外的憑據進行驗證,因此將數據存儲在數據庫中會更安全。可以添加 SSL 以獲得更安全的鏈接。)但是,如果在 UI 中已經顯示了該專用數據,那么您應該已經確認了鏈接的安全性。在這種情況下,將同樣的值放入 ViewState 不會降低安全性。
    • 尚未序列化到 ViewState 中的對象,如 DataSet。ViewState 序列化程序只為一小部分常用的對象類型進行了優(yōu)化,如下所示。其他可序列化的類型或許可以保留在 ViewState 中,但速度會變慢,并會生成一個非常大的 ViewState。
    ?會話狀態(tài)ViewState
    是否使用服務器資源?
    是否超時?是,20 分鐘后(默認)
    是否存儲所有 .NET 類型?否,僅支持:String、Integer、Boolean、Array、ArrayList、Hashtable 和自定義 TypeConverter
    是否增加“HTML 有效負載”?

    使用 ViewState 獲得最佳性能

    使用 ViewState 時,每個對象都必須先序列化到 ViewState 中,然后再通過回傳進行反序列化,因此使用 ViewState 并非是沒有代價的。但是,如果遵循某些簡單的原則對 ViewState 的成本加以控制,則通常不會產生明顯的性能影響。

    • 在不需要時禁用 ViewState。下面的“減少使用 ViewState”一節(jié)將詳細介紹這一問題。
    • 使用優(yōu)化過的 ViewState 序列化程序。上面列出的類型具有專門的序列化程序,這些程序運行速度很快,并已經過優(yōu)化,可以生成很小的 ViewState。如果要序列化一個未在上面列出的類型,可以創(chuàng)建一個自定義 TypeConverter 來顯著提高它的性能。
    • 盡量減少使用對象,如果可能,盡量減少放入 ViewState 中的對象的數目。例如,不要使用二維字符串數組(名稱/值,其對象的數目與數組的長度一樣多),而應使用兩個字符串數組(只有兩個對象)。但是,在將兩個已知類型存儲在 ViewState 中之前,在這兩者之間轉換不會獲得任何性能提高,因為這樣做實際上相當于付出了兩次轉換的代價。

    減少使用 ViewState

    默認情況下 ViewState 將被啟用,并且是由每個控件(而非頁面開發(fā)人員)來決定存儲在 ViewState 中的內容。有時,這一信息對應用程序并沒有什么用處。盡管也沒什么害處,但卻會明顯增加發(fā)送到瀏覽器的頁面的大小。因此如果不需要使用 ViewState,最好還是將它關閉,特別是當 ViewState 很大的時候。

    可以基于每個控件、每個頁面或每個應用程序來關閉 ViewState。在以下情況中將不再需要 ViewState:

    頁面控件
    • 頁面不回傳給自身。
    • 處理的不是控件的事件。
    • 控件沒有動態(tài)的或數據綁定的屬性值(或對于每一個請求它們都設置在代碼中)。

    DataGrid 控件是 ViewState 的一個重量級用戶。默認情況下,在網格中顯示的所有數據也都存儲在 ViewState 中,當需要一個復雜的操作(如復雜的搜索)來獲取數據時,這是非常有用的。但是,DataGrid 的這種行為有時也使得 ViewState 成為累贅。

    例如,這里有一個簡單的頁面就屬于上述情況。因為頁面不回傳給自身,所以它并不需要 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 時,這個小網格會給該頁面增加 3000 多字節(jié)的 HTML 有效負載!使用 ASP.NET Tracing(英文)或查看發(fā)送到瀏覽器的頁面的源代碼(如以下代碼所示),可以清楚地看到這一點。

    <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 只是進行了 Base64 編碼,以確保值在往返過程中不會發(fā)生變化,而并不考慮應用程序使用的響應/請求編碼。

    可以向應用程序中添加兩種 ViewState 安全級別:

    • 防篡改
    • 加密

    需要注意的是,ViewState 安全性對于處理和呈現 ASP.NET 頁面所需的時間有直接的影響。簡單地說,安全性越高,速度越慢。因此如果不需要,請不要為 ViewState 添加安全性。

    防篡改

    盡管散列代碼不能確保 ViewState 字段中實際數據的安全,但它能夠顯著降低有人通過 ViewState 騙過應用程序的可能性,即防止回傳應用程序通常禁止用戶輸入的值。

    可以通過設置 EnableViewStateMAC 屬性來指示 ASP.NET 向 ViewState 字段中追加一個散列代碼:

    <%@Page EnableViewStateMAC=true %>
    

    可以在頁面級別上設置 EnableViewStateMAC,也可以在應用程序級別上設置。在回傳時,ASP.NET 將為 ViewState 數據生成一個散列代碼,并將其與存儲在回傳值中的散列代碼進行比較。如果兩處的散列代碼不匹配,該 ViewState 數據將被丟棄,同時控件將恢復為原來的設置。

    默認情況下,ASP.NET 使用 SHA1 算法來生成 ViewState 散列代碼。此外,也可以通過在 machine.config 文件中設置 <machineKey> 來選擇 MD5 算法,如下所示:

    <machineKey validation="MD5" />
    

    加密

    可以使用加密來保護 ViewState 字段中的實際數據值。首先,必須如上所述設置 EnableViewStatMAC="true"。然后,將 machineKey validation 類型設置為 3DES。這將指示 ASP.NET 使用 Triple DES 對稱加密算法來加密 ViewState 值。

    <machineKey validation="3DES" />
    

    Web 領域中的 ViewState 安全性

    默認情況下,ASP.NET 將創(chuàng)建一個隨機的驗證密鑰,并存儲在每個服務器的本地安全授權 (LSA) 中。要驗證在另一臺服務器上創(chuàng)建的 ViewState 字段,兩臺服務器的 validationKey 必須設置為相同的值。如果要通過上述方式之一,對運行于 Web 領域配置中的應用程序進行 ViewState 安全設置,則需要為所有服務器提供一個唯一的、共享的驗證密鑰。

    驗證密鑰是一個包含 20 到 64 位密碼增強字節(jié)的隨機字符串,用 40 到 128 個十六進制字符表示。密鑰越長越安全,因此建議使用 128 個字符的密鑰(如果計算機支持)。例如:

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

    System.Security.Cryptography 名稱空間包括 RNGCryptoServiceProvider 類,使用該類可以生成此字符串,如以下 GenerateCryptoKey.aspx 示例所示:

    <%@ 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();
    
            // 該數組已使用密碼增強的隨機字節(jié)進行填充
            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]));
            }
            
            // 粘貼到文本框,用戶可從中復制
            TextBox1.Text = sb.ToString();
        }
    
    </script>
    

    總結

    ASP.NET ViewState 是一種新的狀態(tài)服務,可供開發(fā)人員基于每個用戶來跟蹤 UI 狀態(tài)。ViewState 沒有什么神秘之處,它只是利用了一個老的 Web 編程技巧:在一個隱藏的窗體字段中來回傳遞狀態(tài),并將它直接應用于頁面處理框架中。但效果卻非常好 - 在基于 Web 的窗體中只需編寫并維護很少的代碼。

    用戶可能并不總是需要它,但我想您在需要它的時候會發(fā)現,ViewState 是提供給頁面開發(fā)人員的諸多 ASP.NET 新功能中非常令人滿意的一種功能。

    posted on 2006-11-21 10:55 注銷..... 閱讀(158) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲一级毛片免观看| 亚洲人成无码网站久久99热国产| 亚洲开心婷婷中文字幕| 日本永久免费a∨在线视频| 亚洲国产av一区二区三区| 日本一区二区在线免费观看| 天堂亚洲免费视频| 日本在线观看免费高清| 国产亚洲AV夜间福利香蕉149| 国产高潮流白浆喷水免费A片 | 中文字幕在线亚洲精品 | 免费看的一级毛片| 亚洲国产精品无码久久| 日本免费人成黄页在线观看视频| 婷婷亚洲综合一区二区| 国产精品亚洲美女久久久| 中文字幕免费视频精品一| 亚洲AV无码乱码国产麻豆穿越 | 一二三四视频在线观看中文版免费 | 亚洲免费在线视频播放| 成年女人免费视频播放77777 | 久久不见久久见免费视频7| 亚洲国产成+人+综合| 国产人妖ts在线观看免费视频| 污网站免费在线观看| 久久久亚洲精品国产| 1024免费福利永久观看网站| 亚洲AⅤ男人的天堂在线观看 | 成人人观看的免费毛片| 羞羞视频免费观看| 亚洲人色婷婷成人网站在线观看| 亚洲啪啪免费视频| 羞羞网站免费观看| 亚洲精选在线观看| 国产又粗又长又硬免费视频| 国产免费爽爽视频在线观看| 亚洲一区AV无码少妇电影| 亚洲色婷婷综合久久| 毛片a级毛片免费观看免下载| CAOPORN国产精品免费视频| 久久国产亚洲高清观看|