C# 中 viewstate 3篇文章

在asp时代, 一个html控件的值(比如input 控件值),当我们把表单提交到服务器后, 页面再刷新回来的时候, input里面的数据已经被清空. 这是因为web的无状态性导致的, 服务端每次把html输出到客户端后就不再于客户端有联系.

    asp.net巧妙的改变了这一点. 当我们在写一个asp.net表单时, 一旦标明了 form runat=server ,那么,asp.net就会自动在输出时给页面添加一个隐藏域

< input type ="hidden" name ="__VIEWSTATE" value ="" >

    那么,有了这个隐藏域,页面里其他所有的控件的状态,包括页面本身的一些状态都会保存到这个控件值里面. 每次页面提交时一起提交到后台,asp.net对其中的值进行解码,然后输出时再根据这个值来恢复各个控件的状态. 我们再看这个控件的value值,它可能类似如下的形式:Oz4+O2w8aTwxPjs+O2w8.... 很多人会认为这是加密的信息,其实不是, ms仅仅是给各个控件和页面的状态存入适当的对象里面,然后把该对象序列化, 最后再做一次base64编码,直接赋值给viewstate控件.

    viewstate与session有什么关系?

    在后台aspx.cs代码里:

private void Page_Load( object sender, System.EventArgs e) { ViewState[ " myvalue " ] = " viewstatevalue " ; // ..... }
      可以在页面后台直接给viewstate集合赋值, 你也许觉得和session的使用方法差不多了呢? 对,这一点就是几乎所有初学asp.net的人的疑惑. 会认为asp.net也像session那样把这个值保存到服务器内存里面, 其实不是!

    那么,这里的viewstate值是属于谁?又存在哪里? 其实,它和其他控件的状态保存一样,也是存储到那个隐藏的viewstate控件值里面, 上面已经说了, viewstate用来保存状态,包括页面本身, 那么,这里的viewstate就属于页面本身的状态.

    viewstate与session的对比

    (1) session值是保存在服务器内存上,那么,可以肯定,大量的使用session将导致服务器负担加重. 而viewstate由于只是将数据存入到页面隐藏控件里,不再占用服务器资源,因此, 我们可以将一些需要服务器"记住"的变量和对象保存到viewstate里面. 而sesson则只应该应用在需要跨页面且与每个访问用户相关的变量和对象存储上. 

     (2) session在默认情况下20分钟就过期,而viewstate则永远不会过期.

      但viewstate并不是能存储所有的.net类型数据,它仅仅支持String、Integer、Boolean、Array、ArrayList、Hashtable 以及自定义的一些类型.

      任何事物都有两面性, 使用viewstate会增加页面html的输出量,占用更都的带宽,这一点是需要我们慎重考虑的. 另外, 由于所有的viewstate都是存储在一个隐藏域里面,用户可以很容易的通过查看源码来看到这个经过base64编码的值.然后再经过转换就可以获取你存储其中的对象和变量值.

 

C# TextBox的EnableViewState为false后,为什么点击按钮PostBack,TextBox的内容还还是会保持(Persist)

 

Page对象的EnableViewState属性为false,意味着整个页面(包括其中的所有服务器端控件)的ViewState被禁用,但是<input type="hidden" name="__VIEWSTATE" value="...." />并不消失,这个时候ViewState是不起作用的。

TextBox的文本内容会放置在Post到服务器的数据集合里面,然后TextBox实现了IPostBackDataHandler接口,它会在Page_Load事件之前调用IPostBackDataHandler.LoadPostData 方法来根据Post回来的Html元素的name属性与服务器端控件的UniqueID属性相匹配来更新响应TextBox.Text属性,然后,如果这个新的数据与老的Text属性不一样了,则LoadPostData返回true,这样后面的RaisePostDataChangedEvent将会被调用,这个事件最后会调用OnTextChanged方法触发TextBox.TextChanged事件,然后,最后在Render事件里面,TextBox将会将其Text属性Render出来,这样,最终显示的TextBox内容还是会保持。(注意,这里UniqueID属性非常重要,一定要在Render的时候将name属性设置为UniqueID,否则LoadPostData方法将不能够找到正确的服务器端控件匹配,具体参考最后的“Processing Postback Data”)

注意:虽然TextBox的Text属性是使用ViewState来实现的而此时ViewState被禁用,但是ViewState被禁用只是意味着LoadViewState和SaveViewState方法并不会将服务器内容中的ViewState对象内容保存在<input type="hidden" name="__VIEWSTATE" value="...." />里面,内存中的ViewState对象还是可以使用的,可以证明如下:
private void Page_Load(object sender, System.EventArgs e)
{
this.ViewState["test"]="test";
this.Response.Write(this.ViewState["test"].ToString());
}

在ViewState被禁用的情况下,"test"字符串还是会被写出来的,这说明内存中的ViewState对象还是可以使用的。

 

 

 

浅析ASP.NET禁用ViewState


    前段时间由于程序出现了比较大的性能问题,视图(View)之间的跳转速度非常慢。通过Fiddler调试和分析,查找到是由于在视图(View) 转换(PostBack)过程中,客户端给服务器端的发送字节数非常大,一般在30K以上,就相当于客户端每次都要给服务器上传大十K的数据量,这如果是比较好的网络环境下完全是可以忽略的,但是目前的网络环境确实还达不到这样的要求。详细请看《无刷新视图跳转的局限性》。针对这一情况,我的解决方案就是禁用页面的ViewState,只有这样才是最根本的解决办法。原本还想写一篇blog来好好批一下ViewState,当初想好的标题是“ASP.NET程序的性能杀手----ViewState”。现在看来,还好没写,要不还不被人批是“没有真正会用 ASP.NET 的人”?(尽管确实还没有真正全面认识ASP.NET)。

    在jillzhang的blog《给页面减减肥!》中给页面减肥的办法是对页面进行压缩。这确实是一种办法,特别是当在硬件环境允许的条件下,可以带来非常大的好处,一般体积都可以减小好几倍。减小页面体积还有一种办法,那就是ASP.NET禁用ViewState,两种方法并不是互斥的,而且我认为只有禁用ViewState后,页面压缩的效果才更明显的。因为ViewState的值本身就是一些相对紧凑的字符,而HTML代码则相对松散,(我也不是特别肯定这对压缩有必然的联系。)。最近一直在从事页面速度的优化方面的工作,所以很多平常不注意的细节,它所造成的性能影响在这时候就体现出来了。一般的页面(服务器控件比较多)如果ASP.NET禁用ViewState后,它的体积至少会减小一半。而且这一半的数据在很多情况都是没用的(特别是在不需要PostBack的情况下,简直就是累赘),如果这时候再加HTML压缩的话,那压缩比就不止3-5倍了。有一个页面正常的大小(ASP.NET禁用ViewState后)是101,730 byte ,压缩后变成了11,182 byte。说实话我也很惊讶这样的压缩比。通过这里可以看这组惊人数据。

    那这一切是不是都是ASP.NET的错呢?ViewState是不是就是“万恶之源”呢?是,也不是。为什么呢?首先我们要正确认识ViewState存在的意义,更多的情况下MS是为我们这些新手快速入门而考虑的。正因为有了ViewState,让我们开发B/S应用程序能够按照我们的正常的思维逻辑来进行。而屏蔽了在PostBack时,还要去初始化一堆的页面控件,给这个控件还原我们提交的请求值等等,想想这对于我们来说是多少复杂而麻烦的一项工作啊!而不是像我们现在这样,直接在PostBack事件取我们想要的控件的值这么简单。而默认情况下ViewState=true,也是在为初学者着想的,不至于让一个初学ASP.NET的同学在写postback事件时出现一些奇怪的错误而灰心丧气,提高门坎。一段个人的理解可能还不能让一些朋友看得很明白,关于ViewState的讨论已经很多了,但是最重要一点就是理解页面的执行生命周期。如果把下面这张图啃下去后你也许就会有深刻理解了。


    谈点有意义的吧?是禁还是用?决定因素有以下几点(个人理解):

    1.你的目标应用环境。

    这是最根本的,如果你的ASP.NET应用程序只在局域网(Intertrant)内应用的话,那非常棒,我们完全可以忽略ViewState存在的影响。

    2.页面的性质。

    如果你的页面是一种信息浏览的性质,而完全没有PostBack事件的话。这里的ViewState就完全是可以被消灭的。反之,如果页面中有PostBack事件,尽管只有一个,那你如果禁用了ViewState,都有可能产生不可预期的错误。

    3.你对ViewState和页面事件的理解程度。

    如果你很理解页面的生命周期和执行过程,那你完全可以根据需要来设置哪些控件需要打开ViewState,哪些控件可以禁用ViewState,做到按需使用,合理使用ViewState。达到性能的最优化。

    4.开发人员的勤劳程度和外在因素。

    如果你很勤劳,而且你也了解了ViewState的原理,你可以按需使用。但是如果你很懒,而且很多外在因素(团队其它成员的理解程度)你没无法控制的话,那就直接禁用页面的ViewState好了。当然前提是你必须知道如果去正确处理禁用ViewState后遗留下的问题,这些问题一般都是一些让人难以捉摸的东西。如果你都是一一的解决了这些问题的话,那对ViewState的感情就更深了。呵呵。

    可以这么说ViewState是页面控件状态的一个副本,比如一个DropDownList控件,它在ASP.NET页面上要是以select HTML tag 来展现的,而这时在ViewState中还保存着它所有Item的副本。当我们在postback的时候为什么能够取到值呢?就是因为ViewState,它会在ProcessPostData(before Load)之前将这个副本还原成了DropDownList的Item了。然后在ProcessPostData方法中将表单提交的选择项设置为 DropDownList的SelectedValue。以前这一过程我们无需参与。而当ASP.NET禁用ViewState后,我们就要手动去维护DropDownList回发情况下的Item初始化,利用Request.Params(或Request.Form)取得SelectedValue值等等,而这些工作有可能就要在Page_Load事件之前做了。

     
     
    • 1
      点赞
    • 2
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值