為Web頁面及其控制項保持狀態資訊是非常有必要的。然而,由於Web應用程式創建於HTTP協議的頂層,這是一個無狀態的協議,因此,保持狀態資訊變得非常困難。為了解決這個問題,ASP.NET 2.0技術提供了多種解決方案,例如,利用Session、Cookie、視圖狀態、控制項狀態、隱藏網域、查詢字串、個人化使用者配置(Profile)等等。對於利用ASP.NET 2.0技術建立伺服器控制項而言,保持狀態資訊也是非常重要的,其主要解決途徑是利用視圖狀態和控制項狀態。本文詳細講解了視圖狀態(ViewState)的基本知識,並透過典型應用介紹視圖狀態的應用方法。
視圖狀態概述
視圖狀態是一項非常重要的技術,它能讓頁面和頁面中的控制項在從伺服器到客戶端,再從客戶端回傳的往返過程中保持狀態資訊。這樣就可以在Web這種無狀態的環境之上創造一個有狀態並持續執行的頁面效果。本節主要介紹視圖狀態的運作機制、應用方法、儲存的資料型態、效能與安全性、視圖狀態分塊(這是ASP.NET 2.0的新功能)和優缺點等內容。
(1)運行機制
視圖狀態的具體運作過程為:每當使用者請求某個.aspx頁面時,.NET框架先將相關控制項的狀態資料序列化成一個字串,然後,將其做為名為__VIEWSTATE的隱藏域的Value值會傳送到客戶端。如果頁面是第一次被要求,那麼伺服器控制項也會是被第一次執行時,名為__VIEWSTATE的隱藏域中只包含控制項的預設信息,通常為空或null。在隨後的回送事件中,ViewState中就保存了伺服器控制項在前面回送中可用的屬性狀態。這樣伺服器控制項就可以監視目前被處理的回送事件發生之前的狀態了。這些過程是由.NET框架負責的,對使用者來說是執行.aspx頁面就有了持續執行的效果。
(2)儲存的資料類型
視圖狀態可以儲存多種類型的數據,為了提高運作效率,視圖狀態本身也包含一套已最佳化的針對常用類型的序列化方式。視圖狀態序列化方式預設支援的資料類型包括以下幾種:String、Int32、Unit、Color、Array、ArrayList、HashTable和自訂類型轉換器TypeConverter。
視圖狀態已經為Array、ArrayList和包含上面列出類型的HashTable物件進行了最佳化。因此,當在控制項中使用視圖狀態時,應該試著限定於使用以上簡單資料類型,以及經過最佳化的類型。在此,需要重點說明一下自訂類型轉換器TypeConverter,它提供了一種將值的類型轉換為其他類型以及存取標準值和子屬性的統一方法。例如,可以利用TypeConverter將字串轉換為數值,或將數值轉換為字串。如果沒有類型轉換器,那麼頁面框架會使用.NET框架提供的二進位序列化功能來序列化對象,這個過程是非常耗費資源的。
(3)效能和安全性
使用視圖狀態時,物件必須先序列化,然後再透過回傳進行反序列化。因此,我們必須了解有關ViewState效能的內容。預設情況下,控制項的ViewState將會啟用,如果不需要使用ViewState,最好還是將它關閉。以下情況將不再需要ViewState:(1)控制項未定義伺服器端事件(這時的控制項事件均為客戶端事件且不參加回送的);(2)控制項沒有動態的或資料綁定的屬性值。關閉視圖狀態的方法是將控制項的EnableViewState的值設為"false",即EnableViewState="false"。
預設情況下,視圖狀態的相關內容在編譯運行發送給客戶端時,讀者將在頁面的HTML程式碼中看到__VIEWSTATE隱藏域內容。這是一些沒有意義的字串,是.NET框架透過Base64位元編碼對相關內容編碼的結果。它們是透過明文方式在客戶端和伺服器端之間往返傳送。在某些情況下,例如涉及密碼、帳號、連接字串等敏感內容時,使用預設方式是很不安全的。為此,.NET框架為ViewState提供了兩種安全機制:
· 校驗機制:
可以透過設定EnableViewStateMAC="true"屬性來指示.NET框架向ViewState資料中追加一個雜湊碼(該雜湊碼是一種SHA1類型,長度有160位,因此會嚴重影響執行效能)。在回傳事件發生時,將重新建立該散列碼,它必須和最初的雜湊碼相符。透過這種方式,能夠有效檢驗ViewState是否在傳送過程中能夠被竄改。預設情況下,.NET框架使用SHA1演算法來產生ViewState雜湊程式碼。此外,也可以透過在machine.config檔中設定<machineKey>來選擇MD5 演算法,如下所示:<machineKey validation="MD5" />。 MD5演算法的效能比SHA1演算法好一些,但同樣不夠安全。
· 加密機制
使用加密來保護ViewState欄位中的實際資料值。首先,必須如上所述設定EnableViewStatMAC="true"。然後,將machineKey validation類型設定為3DES,即<machineKey validationKey="AutoGenerate" decryptionKey="AutoGenerate" validation="3DES" />,這指示ASP.NET使用3DES加密演算法加密ViewState值。
(4)視圖狀態分塊
以上內容介紹了視圖狀態的一些基本知識。然而,可能部分讀者會有些疑惑:如果在某些情況下,視圖狀態資料變得很大,那該怎麼辦呢?這樣顯然會出現一些意想不到的後果。為此,ASP.NET 2.0新增了一個名為"視圖狀態分塊"的功能。如果視圖狀態的資料量變得太大,視圖狀態分塊會自動將資料分成多個區塊區,並將這些資料放在多個隱藏形式的欄位中。
若要啟用視圖狀態分塊,可將MaxPageStateFieldLength屬性設定為在單一視圖狀態欄位中允許的最大大小(以位元組為單位)。當該頁回傳到伺服器時,該頁會在頁初始化階段分析視圖狀態字串,並還原頁中的屬性資訊。預設設定是-1,這表示不存在最大大小,不會將視圖狀態分成多個區塊區。
(5)優點與缺點
使用視圖狀態有以下3個優點:一、耗費的伺服器資源較少(與Application、Session相比)。因為,視圖狀態資料都寫入了客戶端計算機中。二、易於維護。預設情況下,.NET系統會自動啟用控制項狀態資料的維護。三、增強的安全功能。視圖狀態中的值經過雜湊計算和壓縮,並且針對Unicode實作進行編碼,其安全性要高於使用隱藏域。
使用視圖狀態有以下3個缺點:一、效能注意事項。由於視圖狀態儲存在頁本身,因此如果儲存較大的值,即使在視圖狀態分塊的情況下,使用者顯示頁面和發送頁面時的速度仍然可能會減慢。二、設備限制。行動裝置可能沒有足夠的記憶體容量來儲存大量的視圖狀態資料。因此,當行動裝置上的伺服器控制項時,將使用其他的實作方法。三、潛在的安全風險。視圖狀態儲存在頁面上的一個或多個隱藏域中。雖然視圖狀態以哈希格式儲存數據,但它可以被篡改。如果直接查看頁輸出來源,可以看到隱藏域中的信息,這導致潛在的安全性問題。
典型應用
在利用ASP.NET 2.0技術進行伺服器控制項開發過程中,有許多方面可以用到視圖狀態。常見的是利用ViewState字典實作伺服器控制項屬性。 ViewState是System.Web.UI.StateBag類型-一個鍵/值對的字典,伺服器控制項的屬性值可以儲存在ViewState中。下面透過一個典型範例,說明ViewState的應用方法。
在自訂伺服器控制項LabelInViewState中,實作了兩個屬性Text和TextInViewState。前者使用私有變數創建,後者使用ViewState實作。它們都用於獲取或設定文字內容。自訂控制項實作檔案LabelInViewState.cs原始碼如下所示。
using System;using System.Collections.Generic; using System.ComponentModel;using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls;namespace WebControlLibrary{ [DefaultProperty("Text")] [ToolboxData("<{0}:LabelInViewState runat=server></{0}:LabelInViewState>")] public class LabelInViewState : WebControl { private string _text; //實作Text屬性public string Text { get { return (_text == null) ? string.Empty : _text; } 設置 { _text = value; } } //使用ViewState實作TextInViewState屬性public string TextInViewState { get { String s = (String)ViewState["TextInViewState"]; return ((s == null) ? String.Empty : s); } set { ViewState["TextInViewState"] = value; } } // 重寫RenderContents方法protected override void RenderContents(HtmlTextWriter output) { output.Write("Text = "); output.Write(Text); output.Write("<br/>"); output.Write("TextInViewState = "); output.Write(TextInViewState); } } } |
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Namespace="WebControlLibrary" Assembly="WebControlLibrary" TagPrefix="sample" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> void Button1_Click(object sender, EventArgs e) { demoLabel.Text = TextBox1.Text; demoLabel.TextInViewState = TextBox2.Text; } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>使用視圖狀態ViewState</title> </head> <body style="font-size: small;"> <form id="form1" runat="server"> <div> 姓名: |
以上程式碼顯示在頁面中包括兩個文字框,兩個按鈕,以及一個自訂伺服器控制項LabelInViewState。如事件處理程序Button1_Click所示,當單擊"提交"按鈕時,LabelInViewState控制項將取得文字方塊中文本,並顯示出來。應用程式效果圖如圖1和圖2所示。
圖1 點選提交按鈕 | 圖2 點選重載按鈕 |