ASP.NET页面状态管理——ViewState的使用

ASP.NET ViewState 设计目的是为了持久化当前页面中的对象的状态,以便下次在页面回发(Postback )后能够还原页面的状态。那么有两点需要注意:

  1. ViewState 只在需要Postback 的页面里才需要使用;
  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 被禁止了,它的分页,排序等信息还是仍然正常工作的。

ASP.NET 的一些设计,如整个页面一个form 元素,以及本文谈到的view state 的使用等,只是在宏观上,概率统计上能达到节约成本,提高效率的目的。但是具体到一个Web 程序, 一个应用场景,一个页面,甚至是一个控件,如果你知到它们背后的东西,你就会更好更正确的去实现它或使用它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值