什么是viewstate?
對于viewstate,我們有許多的誤解。viewstate不保存控件,而是去保存form中對應id控件的值,特別是那些由于他們沒有和form一起post 而在頁面回傳時會丟失的控件的值。viewstate一般不要用來保存session或在頁面間傳輸數據。在頁面回傳后,viewstate不能用來動態地創建頁面的控件。他在頁面回傳之后不回復控件的值。甚至一個控件的viewstate被禁止了,在頁面回傳后,控件的值仍然不會丟失,比如textbox,dropdownlist控件。那什么是viewstate呢?viewstate保存最后一次在服務器上處理的頁面狀態。他不能保存那些被動態改變的控件的值。
viewstate是如何工作的?
所有的服務器端控件都有一個viewstate屬性。如果他是enable的,這個控件的viewstate就起作用了。那viewstate是在哪里,是如何存儲的呢?當一個頁面第一次加載,所有的控件被序列化到viewstate,保存在一個叫_viewstate的隱藏form字段里。這個隱藏字段對應服務器端的viewstate對象。頁面的viewstate使用system.web.ui.statebag對象存儲鍵值對。當一個回傳發生,頁面反序列化viewstate然后恢復所有的控件。頁面中保存控件的viewstate以base 64 編碼格式存儲成name - value。當一個頁面重新加載,會調用兩個和viewstate相關的方法, loadviewstate 和saveviewstate。下面是我的一個頁面中的_viewstate隱藏字段。
<input type="hidden" name="__viewstate" value="dnrato45tm5qzq7oz8ablwpxpje9mml0aq765qncmp2tq==" />
啟用和禁止viewstate
在默認情況下,所有服務器控件的viewstate開啟狀態,通過以及幾種途徑來禁止。
1.頁面級別
2.控件級別
3.應用程序級別
4.機器級別
頁面級別禁止的方法是在頁面的開始寫入
<%@ page enableviewstate ="false" %> 
or 
<%@ page enableviewstate ="true" %>
控件級別是
<asp:textbox id="txtcode" runat="server” enableviewstate="false" />
or
<asp:textbox id="txtcode" runat="server" enableviewstate="true" />
程序級別是在web.config中
<pages enableviewstate="false" />
or
<pages enableviewstate="true" />
機器級別是在machine.config中
<pages enableviewstate="true" enableviewstatemac="true" ... />
or
<pages enableviewstate="false" ... />
在viewstate中保存和取出值
viewstate能處理以下的類型
基本類型,基本類型數組,arraylist 和hashtable,任何可以序列化的對象。
以下代碼是將arraylist存到viewstate中并取出
arraylist obj = new arraylist();
//some code
viewstate["viewstateobject"] = obj;
   obj = viewstate["viewstateobject"];
性能問題
為了更好的頁面呈現性能,viewstate應該盡可能的小。要記住viewstate中的數據會占用很多的網絡帶寬。因此我們要謹慎的利用viewstate。如果頁面和控件不需要回傳,那么就要禁止viewstate屬性。通常在aspx頁面之外保存viewstate會取得更好的性能表現。為了達到這個目的,我們可以使用savepagestatetopersistencemedium 和loadpagestatefrompersistencemedium 這兩個方法。在web.config或machine.config設置來禁止某個程序的所有頁面或全部程序頁面的viewstate。
注意只有控件包含在<form runat=server>里才能存儲viewstate。然而即使頁面所有的viewstate被禁止,頁面仍然在viewstate中保存20字節的數據,用來在回傳時為相應的控件分配viewstate中的數據。所以當頁面完全沒有回傳,移去runat="server"能減少20字節的數據。如果有很多這樣的頁面,20字節的節省也能在一定程度上減少帶寬。viewstate應該在必要的時候使用。在datagrid和datarepeater這樣的控件中要避免使用viewstate,因為這些控件的viewstate占用數據相當大。
下面我提供一個簡單的用于計算頁面viewstate大小的方法。創建一個masterpagebase 類,然后其他所有的頁面都要繼承他。
public class masterpagebase: system.web.ui.page
...{
  protected override void onprerender(eventargs e)
  ...{
    object viewstateobject = httpcontext.current.request["__viewstate"];
    if (viewstateobject == null)
      httpcontext.current.trace.warn("the viewstate size is:", "0");
    else
      httpcontext.current.trace.warn("the viewstate size is:",
        httpcontext.current.request["__viewstate"].length.tostring());
    base.onprerender(e);
  }
}
安全問題
可以采取兩個措施來避免viewstate被仿冒
使用enableviewstatemac屬性
給 viewstate中的內容加密
enableviewstatemac會進行一個機器授權驗證(mac),這應在頁面級別或程序級別使用。當設置時,這個屬性會在viewstate呈現之前附加一個viewstate的hash值。當回傳發生時,hash值會被重新計算和核對。如果他們不匹配,頁面會拒絕顯示,這樣就確保了viewstate沒有被纂改。
在machine.config中設置對viewstate內容的加密
<machinekey validation="3des" /> or <machinekey validation="sha1"/>
viewstate容易出錯的地方
當將一個頁面的控件傳輸到另外一個頁面(第二個頁面)時,通常會出現錯誤。解決方法是在第二個頁面中將viewstate禁用。
 
新聞熱點
疑難解答
圖片精選