原文鏈接:
ViewState: All You Wanted to Know
作者:
Paul Wilson
翻譯
:木野狐
ViewState 不是什么?
1. ViewState 不是用來恢復回發的控件的值。
這個是通過匹配 form 中該控件的變量名而自動完成的。這個只對 Load 事件加載之前創建的控件有效。
2. ViewState 不會自動重新創建任何通過代碼動態創建的控件。
3. 不是用來保存用戶信息的。僅僅保存本頁的控件狀態,而不能在頁面之間傳遞。
ViewState 是什么?
ViewState 用來跟蹤和保存控件的狀態信息。否則這些信息可能會丟失,原因可能是這些值不隨著 form 回發,或者根本就不在 page 的 html 中。
ViewState 中保存著代碼中改變的控件屬性,通過代碼綁定到控件的任何數據,以及由用戶操作觸發,回發的任何更改。
ViewState 還提供了一個狀態包(StateBag), 這是一個特殊的集合或字典(collection or dictionary), 可以用來保存,通過一個 key 來恢復任意的對象或者值。
ViewState 的格式
保存在表單中的 __VIEWSTATE 隱藏字段。是 Base64 編碼過的,而不是加密!
但要加密也是可以的(設置 enableViewStateMac 來使用 machine key 進行 hash)
加密:設置 machineKey 驗證, 但這必須在機器級別設置,需要更多的資源,所以不推薦。
Listing 1: ViewState Machine Hash Disabled
machine.config or web.config : <pages enableViewStateMac='false' /> page level directive : <%@Page enableViewStateMac='false' %> page level script code : Page.EnableViewStateMac = false;
Listing 2: ViewState Encryption is Enabled
machine.config : <machineKey validation='3DES' validationKey='*' /> where the validationKey must be the same across a web-farm setup also requires the enableViewStateMac property setting to be true
在 rendering 之前,ViewState 在 Page.SavePageStateToPersistenceMedium 方法中被保存,
回發時,在 Page.LoadPageStateFromPersistanceMedium 方法中被恢復。
這兩個方法都可以輕易的被重寫,從而實現保存 ViewState 到 Session 中。這適合于帶寬小的場合,
如移動設備默認是采用 Session.代碼如下:
Listing 3: ViewState Saved in Session State
protected override object LoadPageStateFromPersistenceMedium() { return Session["ViewState"]; } protected override void SavePageStateToPersistenceMedium(object viewState) { Session["ViewState"] = viewState; // Bug requires Hidden Form Field __VIEWSTATE RegisterHiddenField("__VIEWSTATE", ""); }
如果要把 ViewState 通過數據庫或其他持久化設備來維持,則需要采用特定的 LosFormatter 類來序列化,反序列化。(serialize, deserialize)
Listing 4: ViewState Saved in Custom Store
protected override object LoadPageStateFromPersistenceMedium() { LosFormatter format = new LosFormatter(); return format.Deserialize(YourDataStore["ViewState"]); } protected override void SavePageStateToPersistenceMedium(object viewState) { LosFormatter format = new LosFormatter(); StringWriter writer = new StringWriter(); format.Serialize(writer, viewState); YourDataStore["ViewState"] = writer.ToString(); } 最后,我們來看一下 ViewState 的內部格式到底是什么。 每個控件的 ViewState 保存在一個三元組中(Triplet, System.Web.UI.Triplet). 其 First 對象是: 一個 Pair(System.Web.UI.Pair) 或 Array or Pairs, of ArrayLists of related name-values. Second 對象: 該控件在控件樹中的索引的 ArrayList Third 對象: 子控件的類似的三元組的 ArrayList
Listing 5: ViewState Decode/Parse Example
編碼后的 ViewState : dDwxMjM0NTY3ODkwO3Q8cDxsPHBycEE7cHJwQjtwcnBDOz47bDx2YWxBO3ZhbEI7dmFsQzs+PjtsPGk8 MD47aTwyPjtpPDM+O2k8NT47PjtsPHQ8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8 cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2 YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+Oz4+Oz4= 解碼后的 ViewState : t<1234567890;t<p<l<prpA;prpB;prpC;>;l<valA;valB;valC;>>; l<i<0>;i<2>;i<3>;i<5>;>;l< t<p<l<prpA;prpB;>;l<valA;valB;>>;;>; t<p<l<prpA;prpB;>;l<valA;valB;>>;;>; t<p<l<prpA;prpB;>;l<valA;valB;>>;;>; t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;>>;> 解析后的 ViewState : t<1234567890; 頁面級別的三元組是特例 t<p<l<prpA;prpB;prpC;>; Triplet-First:Pair-First:ArrayList l<valA;valB;valC;> Pair-Second:ArrayList >; l<i<0>; Triplet-Second:ArrayList:Indices i<2>; of the i<3>; Children i<5>; Controls >; l<t<p<l<prpA;prpB;>; Triplet-Third:ArrayList:Triplets l<valA;valB;> of the >; Children ; Controls >; t<p<l<prpA;prpB;>; Each Sub-Triplet follows same Pattern l<valA;valB;> >; ; More Levels Possible if sub-Children >; t<p<l<prpA;prpB;>; Each Sub-Triplet follows same Pattern l<valA;valB;> >; ; More Levels Possible if sub-Children >; t<p<l<prpA;prpB;>; Each Sub-Triplet follows same Pattern l<valA;valB;> >; ; More Levels Possible if sub-Children >; > >; Closing of Special Page-Level Triplet >
Listing 6: ViewState Decode/Parse Code
1 using System; 2 using System.Collections; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Web; 7 using System.Web.SessionState; 8 using System.Web.UI; 9 using System.Web.UI.WebControls; 10 using System.Web.UI.HtmlControls; 11 using System.IO; 12 using System.Text; 13 14 namespace MyPlayground 15 { 16 /// <summary> 17 /// ShowViewState 的摘要說明。 18 /// </summary> 19 public class ShowViewState : System.Web.UI.Page 20 { 21 private void Page_Load( object sender, System.EventArgs e) 22 { 23 //Trace.Warn("分類名稱", "^_^,這是警告!自動用紅色字顯示"); 24 //Trace.Write("這是普通的消息寫入!"); 25 } 26 #region Web 窗體設計器生成的代碼 ... #endregion 47 48 protected override void SavePageStateToPersistenceMedium( object viewState) 49 { 50 // 調用基類的方法以便不影響正常的處理 51 base .SavePageStateToPersistenceMedium(viewState); 52 // 讀取 ViewState 并寫到頁面 53 LosFormatter format = new LosFormatter(); 54 StringWriter writer = new StringWriter(); 55 format.Serialize(writer, viewState); 56 string vsRaw = writer. ToString (); 57 Response.Write( "ViewState Raw: " + Server.HtmlEncode(vsRaw) + "<hr>" ); 58 // 解碼 ViewState 并寫到頁面 59 byte [] buffer = Convert.FromBase64String(vsRaw); 60 string vsText = Encoding.ASCII.GetString(buffer); 61 Response.Write( "ViewState Text: " + Server.HtmlEncode(vsText) + "<hr>" ); 62 // 解析 ViewState -- 打開頁面跟蹤(Tracing) 63 ParseViewState(viewState, 0); 64 } 65 private void ParseViewState( object vs, int level) 66 { 67 if (vs == null ) 68 { 69 Trace.Warn(level. ToString (), Spaces(level) + "null" ); 70 } 71 else if (vs. GetType () == typeof (System.Web.UI.Triplet)) 72 { 73 Trace.Warn(level. ToString (), Spaces(level) + "Triplet" ); 74 ParseViewState((Triplet) vs, level); 75 } 76 else if (vs. GetType () == typeof (System.Web.UI.Pair)) 77 { 78 Trace.Warn(level. ToString (), Spaces(level) + "Pair" ); 79 ParseViewState((Pair) vs, level); 80 } 81 else if (vs. GetType () == typeof (System.Collections.ArrayList)) 82 { 83 Trace.Warn(level. ToString (), Spaces(level) + "ArrayList" ); 84 ParseViewState((IEnumerable) vs, level); 85 } 86 else if (vs. GetType ().IsArray) 87 { 88 Trace.Warn(level. ToString (), Spaces(level) + "Array" ); 89 ParseViewState((IEnumerable) vs, level); 90 }
ViewState 剖析(翻譯兼筆記) (轉自http://www.zahui.com/html/4/8435.htm)
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
