zoukankan      html  css  js  c++  java
  • 禁掉VIEWSTATE之后(二)

    禁掉VIEWSTATE之后(一)发布以后,获得了很多评论,让我很是鼓舞。原以为这是一个说烂了的话题,现在看来,基础的东西永远是值得关注的呀。

    尤其要感谢xiaosuo爱问天徐少侠 等同学的回复,使得我发现了我以往的几个错误认识。重新学习过后,我们开始我们的第二讲的学习研究吧!这一次,我们关注的焦点是:

    1. 什么是VIEWSTATE, 什么不是VIEWSTATE ?
    2. VIEWSTATE和页面生命周期的关系 ?

        VIEWSTATE首先表现为控件(Control)的属性,类型为StateBag。而StateBag实现了IDictionary(所以是一种键值对)和IStateManager。而IStateManager定义了三个方法:LoadViewState、SaveViewState和TrackViewState,一个属性:IsTrackingViewState(再次推荐.NET Reflactor反编译工具,还没有的同学赶快下一个,好东西呀)。望文生义,可以大概猜测得到,VIEWSTATE应该会被加载(Load),被保存(Save);而Track是什么意思呢?

        ASP.NET页面生命周期是一个比较复杂的东西,而和理解VIEWSTATE有关的呢,应该是以下几个:Init、LoadViewState、LoadPostBackData、Load、RaisePostBackEvent和Render几个阶段。下面简要的说明一下:
        1. Init:初始化控件。将页面初始化为一个“控件树”(和DOM树其实很相似),一般来说,根节点就是一个HtmlForm控件,就是由<form runat="server" id="form1"></form>转化而来的。
        2. LoadViewState:这个阶段,有页面Post过来的VIEWSTATE将被解析加载(其实解析和加载还可分为两步,此处不细究)到控件。使得控件被回复到页面被提交之前的状态。

        3. LoadPostBackData:这个阶段和VIEWSTATE没有关系,但能澄清我们很多人的误解!包括我第一节里所犯的最大的错误,为了更清晰的演示,我修改了之前的代码:


    page页面
    <body>
        
    <form id="form1" runat="server">
        
    <div>
            
    <asp:Label ID="Label1" runat="server" Text="I am Label"></asp:Label><br />
            
    <asp:TextBox ID="TextBox1" runat="server" Text="I am TextBox" ></asp:TextBox><br />
            
    <asp:DropDownList ID="DropDownList1" runat="server">
                
    <asp:ListItem Text="I am ListItem (1)"></asp:ListItem>
                
    <asp:ListItem Text="I am ListItem (3)"></asp:ListItem>
                
    <asp:ListItem Text="I am ListItem (2)"></asp:ListItem>            
            
    </asp:DropDownList><br />
            
    <asp:LinkButton ID="LinkButton1" runat="server" Text="I am LinkButton">LinkButton</asp:LinkButton><br />        
            
    <asp:Button ID="Button1" runat="server" Text="I am Button" 
                onclick
    ="Button1_Click" /><br />
            
    <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default2.aspx">HyperLink</asp:HyperLink>
        
    </div>
        
    </form>
    </body>
    cs文件
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Write(Request.Form);

            Label l 
    = new Label();
            l.ID 
    = "lblAdded";
            l.Text 
    = "I am added dynamicly";
            
    this.form1.Controls.Add(l);



        }
        
    protected void Button1_Click(object sender, EventArgs e)
        {
            
    this.Label1.Text = "changed";

            
    this.TextBox1.BorderStyle = BorderStyle.Solid;
            
    this.TextBox1.BackColor = Color.Blue;
            
    this.TextBox1.BorderWidth = 2;

            Label l 
    = this.form1.FindControl("lblAdded"as Label;
            l.Text 
    = "changed";
        }


      按照第一节里的方法运行代码,我们可以发现,禁用VIEWSTATE之后,TextBox里的“值”是仍然可以保存的,但TextBox的边框熟悉不能被保存!所以,可以最直观的回答“什么是VIEWSTATE, 什么不是VIEWSTATE”:TextBox里的“值”不是VIEWSTATE,而TextBox的边框属性就是VIEWSTATE!
      更深一层,我们会发现,TextBox实现了IPostBackDataHandler,而IPostBackDataHandler定义了两个方法:LoadPostData()和RaisePostDataChangedEvent()。TextBox(包括所有实现了IPostBackDataHandler的控件)的“值”是由以上这两个方法实现的,而不是VIEWSTATE,也不是我之前认为的浏览器。
      我们可以通过设置断点,或者通过其他http工具,获得当页面回复时,Request.Form里面的数据(这是在禁用VIEWSTATE的情况下收集的):  
      可以看到TextBox1、DropDownList1和Button1其实是被传送回服务器端的(其实想想这好像是废话,呵呵)。不过注意他们是通过“正常的”<form action=……></form>表单,submit提交的!而不是像VIEWSTATE这样通过hiddenInput提交的。所以他们当然有理由分别处理了!

      4. Load:这个就是我们最熟悉的阶段了,呵呵。到此阶段,所有的控件属性都已经被加载完毕(通过LoadViewState和LoadPostData)。
      5. RaisePostBackEvent:这个阶段其实就是处理我们自己订阅的事件的,典型的如Button_Click。在这个阶段,我们就可能更改控件的状态。这种更改,就应该被记录下来(如果需要的话),而记录这种更改的,正是下面的SaveViewState。
      6. SaveViewState: 在这里,将需要记录保存的VIEWSTATE编码(不是加密)成一个字符串。(是否服务器端会保存一个副本呢?来回传输的是页面全部的控件状态呢,还是变化的?)。
      7. Render:更新过的VIEWSTATE被包含在 hidden input 里,发送到客户端。

      以上就是VIEWSTATE生成的过程。

      但是,如果回头再仔细想一想的话,我们还可能会产生下面的一些疑问:
      是不是所有的控件信息都会被保存为VIEWSTATE?有这个必要么?肯定没有!

      比如在页面上声明的控件属性,

            <asp:Label ID="Label1" runat="server" Text="I am Label"></asp:Label><br />

      每一次页面加载,都会使用页面声明的属性来解析、初始化页面,何必需要VIEWSTATE呢?所以VIEWSTATE根本就不会存储这种信息,它存储的是通过后台程序(cs文件)动态修改的属性,这当然也就包括了通过编程添加的控件。

            Label l = new Label();
            l.ID 
    = "lblAdded";
            l.Text 
    = "I am added dynamicly";
            
    this.form1.Controls.Add(l);

      这也是gridview的VIEWSTATE如此巨大的一个重要原因,GridView里面的子控件全部都是动态生成的呀!

      而更进一步,前面我们说过,VIEWSTATE必须实现三个方法:LoadViewState、SaveViewState和TrackViewState。LoadViewState和SaveViewState都已在相应的页面事件中实现了(Page其实是一个template controls,它会迭代的调用它的子控件中的LoadViewState和SaveViewState方法),所以剩下的就是TrackViewState方法了。该方法在init之后被调用,它将确保所有在此之前(Init完成之前)所获得的控件状态不会被Save!换句话说,VIEWSTATE只记录页面Init之后的控件状态。(你可能会想,那我何不在Init的时候生成GridView,是不是就会大量的减少VIEWSTATA?呵呵,留做思考题吧,我也想想,应该是不可行的。)


      一个很好的参考资料:Understanding ASP.NET View State这篇文章涵盖了本文的所有内容,还包含VIEWSTATE的解析、加密和压缩的内容。而且有详细的图片解说,相当值得一看。
  • 相关阅读:
    Java Logging: Log Levels
    Java Logging: Logger Hierarchy
    Java Logging: Logger
    Java Logging: Basic Usage
    Use final liberally
    Writing Final Classes and Methods
    Java Logging: Overview
    base Tag
    DOM Nodes
    Browser environment
  • 原文地址:https://www.cnblogs.com/freeflying/p/1637316.html
Copyright © 2011-2022 走看看