ViewState 剖析(翻译兼笔记) (转自http://www.

系统 1732 0

原文链接: 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
<script type="text/javascript"> function ToggleSourceCodeRegion(regionNumber) { var divRegion = document.getElementById('region' + regionNumber); var divRegionBlock = document.getElementById('regionBlock' + regionNumber); if (divRegion.style.display == 'inline') { divRegion.style.display = 'none'; divRegionBlock.style.display = 'inline'; } else { divRegion.style.display = 'inline'; divRegionBlock.style.display = 'none'; } } </script>
    
      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 窗体设计器生成的代码
      
      
        ...
      
    
    
      
        27
      
      
        28
      
      
        override
      
      
        protected
      
      
        void
      
       OnInit(EventArgs e)

      
        29
      
      		{

      
        30
      
      
        //
      
      
        31
      
      
        // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
      
      
        32
      
      
        //
      
      
        33
      
      			InitializeComponent();

      
        34
      
      
        base
      
      .OnInit(e);

      
        35
      
      		}

      
        36
      
      
        37
      
      
        /// <summary>
      
      
        38
      
      
        /// 设计器支持所需的方法 - 不要使用代码编辑器修改
      
      
        39
      
      
        /// 此方法的内容。
      
      
        40
      
      
        /// </summary>
      
      
        41
      
      
        private
      
      
        void
      
       InitializeComponent()

      
        42
      
      		{

      
        43
      
      
        this
      
      .Load += 
      
        new
      
       System.EventHandler(
      
        this
      
      .Page_Load);

      
        44
      
      
        45
      
      		}

      
        46
      
    
    
      		#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元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论