1. 程式人生 > >【轉載】ViewState的用法

【轉載】ViewState的用法

log 當我 article 產生 源碼 協議 write 自動 記憶

本文導讀:在web窗體控件設置為runat = "server",這個控件會被附加一個隱藏的屬性_ViewState,_ViewState存放了所有控件在ViewState中的狀態值。ViewState是一個名稱/值的對象集合。當請求某個頁面時,ASP.NET會把所有控件的狀態序列化成一個字符串,然後作為窗體的隱藏屬性送到客戶端,當客戶端吧頁面回傳時,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的原理

1.瀏覽器請求Default.aspx頁面

2.在服務器端 發現創建的ViewState 這個時候 會自動創建一個名字叫做__VIEWSTATE(雙下滑線 全部是大寫)
的隱藏域 其隱藏域的值經過base64加密以後返回到瀏覽器端這一加密過程在頁面生命周期
的SaveState事件中的SaveAllState方法中完成

3.當瀏覽器提交表單的時候 將__VIEWSTATE的隱藏域也一起提交到服務端 這個時候 頁面生命周期的ReadState事件
的ReadAllState方法會將加密後的值反base64解密 最後將值賦值給名字叫做name的ViewState

4.最後來操作ViewState中的值

二、ViewState的用法:

1.定義ViewState屬性

public int PageCount{

get{return (int)ViewState["PageCount"];}

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

}

2.使用ViewState的條件

如果要使用ViewState,則在ASPX頁面中必須要有一個服務器端窗體標記(<form runat = "server">)。窗體字段是必須的,這樣包含ViewState信息的隱藏字段才能被傳回服務器。而且,該窗體還必須是服務器端的窗體,這樣在服務器上執行該頁面時,ASP.net頁面框架才能添加隱藏字段。

page的EnableViewState 屬性值為true

控件的EnableViewState 屬性值為 true

3.ViewState需要註意的地方

a. 當存在頁面回傳時,不需要維持控件的值就要把 ViewState 禁止。
b. ViewState的索引是大小寫敏感的。
c. ViewState不是跨頁面的。

d. 為了能保存在 ViewState中,對象必須是可流化或者定義了 TypeConverter。
e. 控件 TextBox 的 TextMode 屬性設置為 Password時,它的狀態將不會被保存在 ViewState 中,這應該是出於安全性的考慮。
f. 在頁面沒有回傳或重定向或在回傳中轉到(transfer)其他頁面時不要使用 ViewState。

g. 在動態建立控件時要小心它的 ViewState。
h. 當禁止一個程序的 ViewState 時,這個程序的所有頁面的 ViewState 也被禁止了。
i. 只有當頁面回傳自身時ViewState 才是持續的。

4.設置ViewState

ViewState可以在控件,頁,程序,全局配置中設置。缺省情況下 EnableViewState 為 true 。如果要禁止所有頁面 ViewState 功能,可以在程序配置中把 EnableViewState 設為 false 。

三、產生的 __VIEWSTATE如圖

技術分享圖片

使用ViewStateDecoder2(ViewState查看器)來看一下值

技術分享圖片

所以ViewState在安全性上面還是比較差,建議不要存放比較機密和敏感的信息,盡管ViewState可以加密,但是由於ViewState要保存在客戶端,天生就有安全性的隱患。

四、viewstate與session的對比

(1) session值是保存在服務器內存上,那麽,可以肯定,大量的使用session將導致服務器負擔加重. 而viewstate由於只是將數據存入到頁面隱藏控件裏,不再占用服務器資源,因此, 我們可以將一些需要服務器"記住"的變量和對象保存到viewstate裏面. 而sesson則只應該應用在需要跨頁面且與每個訪問用戶相關的變量和對象存儲上.

(2) session在默認情況下20分鐘就過期,而viewstate則永遠不會過期.

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

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


無狀態的根本原因是:瀏覽器和服務器使用Socket通信,服務器將請求結果返回給瀏覽器後,會關閉當前Socket連接,接下來介紹狀態保存機制,感興趣的朋友可以了解下

無狀態Http

無狀態的根本原因是:瀏覽器和服務器使用Socket通信,服務器將請求結果返回給瀏覽器後,會關閉當前Socket連接。而且服務器會在處理頁面完畢後銷毀頁面對象。

應用層面的原因是:瀏覽器和服務器之間通信都遵守HTTP協議。

一個瀏覽者發出的請求都是由實現了IHttpHandler接口的對象進行響應,由於下次訪問不一定還是上次那個對象進行響應,上次響應完畢對象可能已經被銷毀了,寫的類變量值早就不存在了,因此不能將狀態信息保存到類變量中。

編寫一個ashx

復制代碼代碼如下:

private int i; 
public void ProcessRequest(HttpContext context) 
{ 
context.Response.ContentType = "text/plain"; 
context.Response.Write(i++); 
} 

多次刷新我們發現,變量根本不會記憶上次的值。

對網站造成的影響:如果用戶錄入了一些信息,當跳轉到下一個頁面時,數據丟失,再也不能獲得那些數據。

如果要知道上一次的狀態信息,我們就得把這個狀態信息記錄在某個地方:

a.服務器端Session

b.瀏覽器端Cookie

c. 表單元素中—如:隱藏域<input type=“hidden”/>(Http報文)ViewState

技術分享圖片

四個重要的

ViewState:

ASP.NET 的 .aspx頁面特有,頁面級的;

就是在頁面上的一個隱藏域中保存客戶端單獨使用的數據的一種方式;

服務器端控件的值都自動保存在ViewState中;

Cookie:

HTTP協議下的一種方式,通過該方式,服務器或腳本能夠在客戶機上維護狀態信息;

就是在客戶端保存客戶端單獨使用的數據的一種方式;

就像你的病歷本一樣,醫院直接給你帶回家;

Session:和.Net提供的輔助進程相關。

在服務器端保存客戶端單獨使用的數據的一種方式;

就像銀行賬戶,錢都存在銀行裏,你就拿一張銀行卡【所謂的SessionId】回家(寫入客戶端的Cookie中);

Application:

在服務器端保存共享數據的一種方式;

就像銀行的單人公共衛生間,誰進去都行,但一次去一個,進去了就鎖上門,出來再把鎖打開;

ViewState(頁面級)

使用方式: 作用域---頁面級

保存數據方式:

復制代碼代碼如下:

ViewState["myKey"]="MyData";

讀取數據方式:

復制代碼代碼如下:

String myData; 
if(ViewState["myKey"]!=null) 
{ 
myData=(string)ViewState["myKey"]; 
} 

ViewState不能存儲所有的數據類型,僅支持:
String、Integer、Boolean、Array、ArrayList、Hashtable

使用ViewState的前提
頁面上必須有一個服務器端窗體標記(<form runat=“server”>)

服務器在接收到用戶請求一個頁面後,會自動在請求報文中找看是否包含__VIEWSTATE的隱藏域,如果有,則將中間的值解碼後添加到頁面的ViewState屬性中。

服務器在輸出的時候,也會自動的將ViewState中的值添加到表單裏名叫__VIEWSTATE的隱藏域中。

VIEWSTATE適用於同一個頁面在不關閉的情況下多次與服務器交互

跨頁面提交的__VIEWSTATE不會被目標頁面裝入頁面的ViewState屬性中

添加runat=server生成html頁面源碼如下

技術分享圖片

未添加如下:

技術分享圖片

__VIEWSTATE隱藏域生成的原理

復制代碼代碼如下:

//在頁面類對象 執行PR方法的時候 先創建了控件樹 然後通過執行 loadState方法 將請求報文中的名字為__VIEWSTATE的值 然後反base64編碼 進行反序列化 最終還原成為集合 之後將其中屬於程序員自己添加到ViewStatue裏的鍵值對【ViewState會自動添加頁面中runat=server控件的屬性與狀態】還原到頁面對象的ViewState屬性中 最後才執行Page_Load 原理 見圖 
protected void Page_Load(object sender, EventArgs e){ 
//頁面的ViewState屬性實際上就是獲取了瀏覽器提交過來的一個名為__VIEWSTATE的隱藏域裏的值 
if (ViewState["name" ] != null){ 
string strName = ViewState["name" ].ToString(); 
Response.Write( "ViewState[‘name‘]" +strName); 
} else { 
//向 ViewState中添加一個鍵值對 
//ViewState.Add("name", "痞子一毛"); 同以下方式 
ViewState[ "name" ] = "痞子一毛" ; //實質就是向隱藏域中添加鍵值對 如果不被提交到服務器 那麽ViewState["name"]永遠為null 
ViewState[ "name2" ] = "痞子三毛" ; 
} 
}

以上代碼原理圖解:

技術分享圖片

補充:

禁用ViewState的方法,禁用單個控件的ViewState設定enableviewstate=false。禁用整個頁面的,在aspx的Page指令區加上EnableViewState="false" 。內網系統、互聯網的後臺可以盡情的用ViewState。但互聯網前臺就不要使用了【註:禁用也只是不保存服務端控件屬性和值但隱藏域還是存在的】

WebForm的IsPostBack內部實現 就是對頁面或者get傳參中是否含有__ViewState這一參數名稱進行判斷返回bool值

證實:

復制代碼代碼如下:

protected void Page_Load(object sender, EventArgs e){ 
if (IsPostBack) //回傳 
Response.Write( "只要瀏覽器提交的請求報文裏包含__VIEWSTATE這個鍵" );//在該頁面地址 http://localhost:7148/ViewSatate.aspx 末尾添加 ?__VIEWSTATE 會輸出此段代碼 
else 
Response.Write( "ASP.NET就會將頁面的IsPostBack屬性設置為true" ); 
}

【轉自】https://www.cnblogs.com/ooip/p/4743536.html

【轉載】ViewState的用法