viewstate

ViewState 的工作原理
ViewState是一種機制,ASP.NET 使用 這種機制來跟蹤服務器控件狀態值,否則這些值將不作爲 HTTP 窗體的一部分而回傳。例如,由 Label 控件顯示的文本默認情況下就保存在 ViewState 中。作爲開發人員,您可以綁定數據,或在首次加載該頁面時僅對 Label 編程設置一次,在後續的回傳中,該標籤文本將自動從 ViewState 中重新填充。因此,除了可以減少繁瑣的工作和代碼外,ViewState 通常還可以減少數據庫的往返次數。
ViewState 確實沒有什麼神祕之處,它是由 ASP.NET 頁面框架管理的一個隱藏的窗體字段。當 ASP.NET 執行某個頁面時,該頁面上 的 ViewState 值和所有控件將被收集並格式化成一個編碼字符串,然後被分配給隱藏窗體字段的值屬性(即 <input type= hidden>)。由於隱藏窗體字段是發送到客戶端的頁面的一部分,所以 ViewState 值被臨時存儲在客戶端的瀏覽器中。如果客戶端選擇將 該頁面回傳給服務器,則 ViewState 字符串也將被回傳。在上面的圖 2 中可以看到 ViewState 窗體字段及其回傳的值。
回傳後,ASP.NET 頁面框架將解析 ViewState 字符串,併爲該頁面和各個控件填充 ViewState 屬性。然後,控件再使用 ViewState 數據將自己重新恢復爲以前的狀態。
關於 ViewState 還有三個值得注意的小問題。
如果要使用 ViewState,則在 ASPX 頁面中必須有一個服務器端窗體標記 (<form runat=server>)。窗體 字段是必需的,這樣包含 ViewState 信息的隱藏字段才能回傳給服務器。而且,該窗體還必須是服務器端的窗體,這樣在服務器上執行該頁面時, ASP.NET 頁面框架才能添加隱藏的字段。
頁面本身將 20 字節左右的信息保存在 ViewState 中,用於在回傳時將 PostBack 數據和 ViewState 值分發給正確的控件。因此,即使該頁面或應用程序禁用了 ViewState,仍可以在 ViewState 中看到少量的剩餘字節。
在頁面不回傳的情況下,可以通過省略服務器端的 <form> 標記來去除頁面中的 ViewState

在asp時代, 大家都知道一個html控件的值,比如input 控件值,當我們把表單提交到服務器後, 頁面再刷新回來的時候, input裏面的數據已經被清空. 這是因爲web的無狀態性導致的, 服務端每次把html輸出到客戶端後就不再於客戶端有聯繫.

asp.net巧妙的改變了這一點. 當我們在寫一個asp.net表單時, 一旦標明瞭 form runat=server ,那麼,asp.net就會自動在輸出時給頁面添加一個隱藏域

<input type="hidden" name="__VIEWSTATE" value="">

那麼,有了這個隱藏域,頁面裏其他所有的控件的狀態,包括頁面本身的一些狀態都會保存到這個控件值裏面. 每次頁面提交時一起提交到後臺,asp.net對其中的值進行解碼,然後輸出時再根據這個值來恢復各個控件的狀態. 我們再看這個控件的value值,它可能類似如下的形式:Oz4+O2w8aTwxPjs+O2w8....
很多人會認爲這是加密的信息,其實不是, ms僅僅是給各個控件和頁面的狀態存入適當的對象裏面,然後把該對象序列化, 最後再做一次base64編碼,直接賦值給viewstate控件.

說到這,想必你一定想看看這個viewstate裏面到底存了哪些東西, 嗯,你是可以寫一個base64 to string的轉換代碼來實現.不過,viewstate是有層次之分的,普通的轉換後,你看到的也是很亂的文字. 這裏提供了一個專門轉換viewstate值的地方 http://www.wilsondotnet.com/Demos/ViewState.aspx . 你可以去將自己的viewstate輸入進去,讓它給你轉化一下,這可是帶結構的哦 :)

好, 以上說的這些你可能會覺得: 這與session有什麼關係? 這個viewstate不是由asp.net自動去維護嗎? 是的, 如果僅僅是保存控件的狀態, 你可以感覺不到它與session有什麼瓜葛( 呵呵,其實它們就沒有瓜葛),不過,接下來,我們看看這種使用方法: 在後臺aspx.cs代碼裏:

private void Page_Load(object sender, System.EventArgs e) { ViewState["myvalue"] = "viewstatevalue"; //..... }

呵呵, 可以在頁面後臺直接給viewstate集合賦值, 現在你是不是覺得和session的使用方法差不多了呢? 對,這一點就是幾乎所有初學asp.net的人的疑惑. 會認爲asp.net也像session那樣把這個值保存到服務器內存裏面, 其實不是!

那麼,這裏的viewstate值是屬於誰?又存在哪裏? 其實,它和上面的其他控件的狀態保存一樣,也是存儲到那個隱藏的viewstate控件值裏面, 上面已經說了, viewstate用來保存狀態,包括頁面本身, 那麼,這裏的viewstate就屬於頁面本身的狀態.

分析到此,估計大家對viewstate的使用應該是沒有什麼疑問了. 那麼,我們可以來與session做一下類比, session值是保存在服務器內存上,那麼,可以肯定,大量的使用session將導致服務器負擔加重. 而viewstate由於只是將數據存入到頁面隱藏控件裏,不再佔用服務器資源,因此, 我們可以將一些需要服務器"記住"的變量和對象保存到viewstate裏面. 而sesson則只應該應用在需要跨頁面且與每個訪問用戶相關的變量和對象存儲上. 另外,session在默認情況下20分鐘就過期,而viewstate則永遠不會過期.

但viewstate並不是能存儲所有的.net類型數據,它僅僅支持String、Integer、Boolean、Array、ArrayList、Hashtable 以及自定義的一些類型.

當然,任何事物都有兩面性, 使用viewstate會增加頁面html的輸出量,佔用更都的帶寬,這一點是需要我們慎重考慮的. 另外, 由於所有的viewstate都是存儲在一個隱藏域裏面,用戶可以很容易的通過查看源碼來看到這個經過base64編碼的值.然後再經過轉換就可以獲取你存儲其中的對象和變量值.

其實,對於viewstate的安全性問題,asp.net還給我們提供了更多的選擇.一般如果要保護viewstate有兩種方式: 一種是防篡改,一種是加密. 一說到防篡改,我們就想起了使用散列代碼. 沒錯, 我們可以在頁面頂部加入如下代碼:Page EnableViewStateMAC=true

這樣asp.net就會自動的在viewstate中追加一個散列碼,在頁面回傳時,服務器根據回傳的viewstate生成一個散列碼,再與回傳的散列碼相比較,如果不對,則丟棄該viewstate,同時控件將恢復初試狀態. (默認情況下asp.net是通過SHA1算法而不是md5算法來生成散列,不過這個可以在machine.config裏面配置machineKey validation="MD5"即可)

而viewstate加密就更簡單了, 只要在machine.config裏設置一下machineKey validation="3DES"即可實現用des加密viewstate了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章