zoukankan      html  css  js  c++  java
  • ASP.NET ViewState

    ViewState主要是用来维护页面状态的,正所周知,web是无状态的,Asp.Net页面也没有状态,所以在服务器的每个往返的过程中,都有实例化,执行,呈现和处理,如果每次都这样,势必会对服务器造成很大的压力,性能会很低,那么在Asp.Net采用了ViewState机制,对一些不需要重新改变状态的信息,可以保存带到ViewState,总之合理使用ViewState可以在某种程度上大大的提高访问的性能

    但是有些是.net自动帮助我们做好的东西,比如注册的时候,填写完信息后,回发到服务器的时候,这些信息会被自动的保存到服务器中,这些并不是ViewState在启作用,是另外的一种机制

    它是由 ASP.NET 页面框架管理的一个隐藏的窗体字段。当 ASP.NET 执行某个页面时,该页面上的 ViewState 值和所有控件将被收集并格式化成一个编码字符串,然后被分配给隐藏窗体字段的值属性(即 <input type=hidden>)。由于隐藏窗体字段是发送到客户端的页面的一部分,所以 ViewState 值被临时存储在客户端的浏览器中。如果客户端选择将该页面回传给服务器,则 ViewState 字符串也将被回传。

    回传后,ASP.NET 页面框架将解析 ViewState 字符串,并为该页面和各个控件填充 ViewState 属性。然后,控件再使用 ViewState 数据将自己重新恢复为以前的状态。

    ASP.NET ViewState设计的目的是为了持久化当前页面中对象的状态,以便在下次页面回发的时候还原页面的状态,下面两点需要注意:

    1、             ViewState只需要在页面回发的时候才需要使用

    2、             1前提下,只要初始化状态被修改了对象才需要持久化,才需要使用ViewState

    1比较清楚,来谈第2点。以简单的Label控件为例,先来看一下它的Text属性的实现:

    public virtual string Text
    {
       
     get
        {
           
     object obj2 = this.ViewState["Text"];
           
     if (obj2 != null)
            {
               
     return (string) obj2;
            }
           
     return string.Empty;
        }
       
     set
        {
           
     if (this.HasControls())
            {
               
     this.Controls.Clear();
            }
           
     this.ViewState["Text"] = value;
        }
    }

    很显然Text属性的后端都是以ViewState为存储介质的,ASP.NET服务器端控件的很多属性都是以类似方式实现的。假设一个页面default.aspx里只有一个Label控件, <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>,当访问该页面时,Label控件发送到客户端浏览器的代码大概为 <span id="xxx_Label1">Label</span>,同时ViewState中也保存了一份Text属性的值,形式大概为<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTgwMzg2ODMxMQ9kFgJmD2QWAgIDD2QWAg......
    到目前位置,ViewState并没有发挥作用(这里谈论的都是在ViewState Enable的情况下),额外的保存了Text属性的值在这里是多余的。假设该页面还有一个Button控件,点击该按钮页面回发,那么在次过程中ViewState就发挥作用了么?分析一下该页面回发过程中Label控件生命周期的某些过程。首先,回发后,Label控件依然要经历初始化阶段(Init),这个阶段要创建一个Label控件的实例,同时设置其Text属性的,因为Text属性后端是以ViewState为存储介质的,所以就相当于向ViewState里添加了一个值,接下来,因为是回发过程,所以控件还要LoadViewState,即加载前次访问该控件的状态值,下面是Label控件的实现:

    protected override void LoadViewState(object savedState)

    {

        if (savedState != null)

        {

            base.LoadViewState(savedState);

            string text = (string) this.ViewState["Text"];

            if (text != null)

            {

                this.Text = text;

            }

        }

    }

    因为在前一访问过程中ViewState中所保存的LabelText属性的状态值就是Label的初始值,所以导致了这里的LoadViewSate过程是多余的了,而且InitLoadViewState两个过程对Text属性都赋了相同的值。由此可见,即使在页面回发中,如果不需要对属性的初始值进行修改,那么持久化属性的值(即使用ViewState)也是没有意义的。而且会带来多余的资源浪费,如两次对Text属性的赋值,以及增加了ViewSate的体积所带来的多余的网络传输。

    那么,什么情况下使用ViewSate是值得的呢?我们先来把前面例子中两次访问的过程理一下:

    1.            第一次访问页面,Label控件初始化,设置Text属性的值,即向ViewState中添加了一个条目;

    2.            页面发送前(Render前),控件SaveViewState,即ViewSate中的值序列化,保存到一个隐藏域中;

    3.            页面发送,Label控件发送为相应的HTML标签,读取Text属性设置HTML标签的对象属性值,同时发送隐藏域及其值。对于LabeText属性来讲,相当于一份ViewState中的值发送了两份客户端拷贝;

    4.            第二次回发访问,Label控件初始化,设置Text属性的值,即向ViewState中添加了一个条目;

    5.            由于是回发访问,需经历LoadViewState过程,本例中即读取ViewStateText属性在上一次访问中的状态值,而这个值实际上等于过程1中设置的值,读取的值再次设置Text属性,

    6.            第二次发送,重复过程23.

    从过程1控件初始化,到过程6,第二次发送前SaveViewState,在这两个过程中间,如果不需改变Text属性的初始值,那么实际上就不需要使用ViewState。假设我们在过程12中间改变Text属性值,如在Page_Load中如此:

     protected void Page_Loadt(object sender, EventArgs e)
     {
      if (!IsPostBack)
      {
       Label1.Text = "Change Label's value";
      }
     }

     那么,尽管在回发时不能执行Label1.Text = "Change Label's value";语句,但由于ViewState的作用,第一次访问设置的值,在第二次回发访问后仍然会存在,即LabelText属性值为”Change Label's value“,而不是其初始值“Label”。这种情况下才是ViewState的用武之地。注意!IsPostBack的使用,否则你只是每次访问都进行赋值而已,并没有利用ViewState的好处。

    由此,可以得出,在满足前面所述的两个条件时才应该使用ViewState。那么在现实应用中同时满足以上两个条件的情况下多么,也就是说我们需要使用ViewSate的时候多么?

    很显然,满足这两个条件最大宗的情况就是数据绑定。而我认为ViewState的设计目的主要就是为了将必要的信息持久化在页面中,避免在两次访问中(确切的说不只两次,而是所有的回发访问中)都要进行数据绑定(而每次数据绑定往往意味着一次次的数据库访问)。例如用GridView绑定DataSource控件展现一个类表数据,在ViewSate Enable的情况下,页面第一次加载时进行数据绑定,在随后的回发访问中,如果仍是访问当前数据视图,即没有进行分页、排序操作等,DataSource不会再进行数据绑定,因为所有的信息都可以从ViewSate中获取,不需要再次访问数据库再次绑定数据控件了。而如果你将ViewState Disable掉,那么每次访问则都需要进行数据绑定了(可以通过SqlProfiler来捕捉SqlDataSource在两种情况下对数据库的访问情况)。这个场景可能最能说明ViewSate的设计初衷了。

    然而在实际的应用中,上面的这种场景多么?在数据列表页面,往往没有除了分页排序等之外的回发操作(你放Grid的页面里有回发的按钮么?),而分页,排序操作所引起的回发显然是需要数据再绑定的。如果是这种场景,那么你就应该把这个页面或者把这个GridEnableView属性设为false了。这里讲点题外话,有人会说如果设成false,那Grid的分页信息、排序信息怎么传递给后续的回发访问呢?其实在ASP.NET 2.0中控件的状态管理被分为了两部分view statecontrol state。两者的区别是什么呢,那ASP.NET 1.x中的DataGrid控件来说,DataGrid的所有状态信息都保存在view state当中,但是这些信息所符合的view state应用场景是矛盾的,比如你的页面没有回发操作,你不必把所有数据缓存到view state里,这时你会把datagridenableviewstate属性设为false,但当你这么做后,datagrid的另一些功能如翻页、排序,就没法使用了,因为翻页排序的状态信息也是保存在view state中的,如pageindexsort asc/desc等。就类似于这种问题,ASP.NET 2.0中又引入了control statecontrol state的存储方式与view state相同,不同的地方在于它不会被disable掉。这样control state用来存储那些控件的功能性的,必需的信息。比如即使GridViewview state被禁止了,它的分页,排序等信息还是仍然正常工作的。

    前端时间,一个同事在在GirlView控件中进行全选,然后进行删除操作,结果选上之后,执行删除的时候,GirlView的信息都没了,代码大概如下

    If(!ispostback){

    GirlViewBind();

    }

    //绑定

    Public void GirlViewBind()

    {

    //绑定代码

    }

    //执行删除

    ………

    结果很是郁闷,结果去掉If(!ispostback){}然后就好了,后来才知道原来是禁用ViewState,回传之后GirlView的信息都丢失了,当你去掉之后If(!ispostback){}之后相当于又重新实例化,绑定了,其实完全没必要……

    禁用ViewState多种方法,不同方法对应着不同的禁用范围。除了以上例子中直接在服务器控件标签中设置“EnableViewState”属性为“false”,还可以在@Page指令中设置这个属性以达到页面级禁用ViewState的目的。禁用整个WEB应用程序ViewState,修改Web.config中相应元素的属性即可,最后,禁用服务器全局的ViewState,修改.Net Framework安装目录下的machine.config即可。当禁用了ViewState以后,控件还可以通过control state(控件状态)保存状态数据,该属性一般用于自定义控件。
    说明:ViewState只在页面内有效,不能跨页面使用

    关于 ViewState 还有三个值得注意的小问题。
    • 如果要使用 ViewState,则在 ASPX 页面中必须有一个服务器端窗体标记 (<form runat=server>)。窗体字段是必需的,这样包含 ViewState 信息的隐藏字段才能回传给服务器。而且,该窗体还必须是服务器端的窗体,这样在服务器上执行该页面时,ASP.NET 页面框架才能添加隐藏的字段。
    • 页面本身将 20 字节左右的信息保存在 ViewState 中,用于在回传时将 PostBack 数据和 ViewState 值分发给正确的控件。因此,即使该页面或应用程序禁用了 ViewState,仍可以在 ViewState 中看到少量的剩余字节。
    • 在页面不回传的情况下,可以通过省略服务器端的 <form> 标记来去除页面中的 ViewState。

    总结

    ASP.NET ViewState 是一种新的状态服务,可供开发人员基于每个用户来跟踪 UI 状态。ViewState 没有什么神秘之处,它只是利用了一个老的 Web 编程技巧:在一个隐藏的窗体字段中来回传递状态,并将它直接应用于页面处理框架中。但效果却非常好 - 在基于 Web 的窗体中只需编写并维护很少的代码。

    用户可能并不总是需要它,但我想您在需要它的时候会发现,ViewState 是提供给页面开发人员的诸多 ASP.NET 新功能中非常令人满意的一种功能。

    多思考,多创新,才是正道!
  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/shuang121/p/1968736.html
Copyright © 2011-2022 走看看