谁能给我举个例子——什么场合不能禁用Viewstate,谁能举一个鲜活生动的例子



禁掉VIEWSTATE之后(一)

VIEWSTATE无疑是ASP.NET机制中最备受争议的概念之一,很多ASP.NET优化的文章都提到“禁用‘不必要’的VIEWSTATE”,博客园里老赵说过,“我如果新建一个Web项目,做的第一件事情就是去Web.config中将enableViewState从全局关闭”。而持相反的观念的人则质疑,如果没有VIEWSTATE,Web Form还有什么意义?记得csdn上sp1234,曾写过一篇强烈支持VIEWSTATE的文章,反响异常激烈,我通过“csdn sp1234 viewstate”关键字,居然搜出了“駁sp1234之[如果你必须开发交互式页面,ViewState越大可能意味着越有本事]一貼”?遥想当年烽火四起,硝烟弥漫,不觉感慨万千。据说ASP.NET4.0将会默认设置VIEWSTATE=“false”,不知此后争议是否会小一些?高手坐而论道,我们小辈,本是不应该插嘴的,所以我只想把VIEWSTATE彻底弄明白,先。

首先,学老赵,“去Web.config中将enableViewState从全局关闭”。再打开一个空页面看看,是不是清爽了很多。啊?页面源代码中,仍然出现了:


< 
    input  
    type 
    ="hidden" 
     name 
    ="__VIEWSTATE" 
     id 
    ="__VIEWSTATE" 
     value 
    ="/wEPDwULLTE2MTY2ODcyMjlkZI7OBu+sMrYke3ELlQKIiNbArzXe" 
     
    />


居然还有,怎么禁不掉呢?微软动了什么手脚,这不忽悠人吗?(你还可以再试试,页面声明,控件声明,当年我都试过,呵呵)好吧,故事就从这里开始吧!

无论如何,据说VIEWSTATE是“保持页面/控件状态”的,我们先试试看,拖几个控件到页面,先。




< 
     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 
     >




把TextBox的值改掉,假设改成"changed"吧,选中DropDownList的第3项,点Button提交,Postback。结果是什么?
TextBox的值还是changed,DropDownList还是选中的第3项,状态被保存了呀?不是说“http无状态”么?是不是我的VIEWSTATE没被禁掉?难怪页面源代码里还看得见“__VIEWSTATE”!

我还试过按F5刷新,将页面转到另一个页面再“Back”回来,结果我很失望的发现,无论我如何试图禁用viewstate,控件的状态都保持得很好!

后来我被告知,这是浏览器自身的特性,和VIEWSTATE无关,为了验证这一点,我们可以通过纯的html页面进行试验(此处略)。

以上是错误的理解! 真正的原因是因为这些控件实现了IPostBackDataHandler接口,我会在后面的文章中详细解释。


所以,正确的验证VIEWSTATE失效的方式其实是这样的,在后台代码(cs文件)中添加以下代码:





public 
      
     partial 
      
     class 
      _Default : System.Web.UI.Page 
{
 
     protected 
      
     void 
      Page_Load( 
     object 
      sender, EventArgs e)
    {

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





然后,运行。点击Button按钮,你会发现Label已经变成“changed”;然后,再点击LinkButton。你发现了什么?这就是VIEWSTATE=“false”时的效果,也应该是正常的效果。我认为这还是好理解的,除了“HTTP无状态协议”以外,你还可以这样想:“当我点Button的时候,会触发ButtonClick事件,所以Label会改变;而我点击ImageButton的时候,页面会重新加载,却不会触发ButtonClick事件,所以Label也就自然按页面声明的那样显示了”。(这本是事物的本原,被微软默认使用了viewstate之后,事情反而变得更难以理解了,微软啊微软!)

好吧,我们再看看使用了viewstate之后的效果。在当前页面声明如下,


<% 
    @ Page Language 
    = 
    " 
    C# 
    " 
     AutoEventWireup 
    = 
    " 
    true 
    " 
      CodeFile 
    = 
    " 
    Default.aspx.cs 
    " 
     Inherits 
    = 
    " 
    _Default 
    " 
     EnableViewState 
    = 
    " 
    false 
    " 
     
    %>



哈哈,你又上当了!注意,viewstate的设置规则是:但你在上一级(如web.config)禁用了viewstate,你在下级(page/control)里是无法再启用的。(所以viewstate目前使用起来还是不不方便的。无论如何,asp.net4.0就好了)

xiaosuo 在后面的评论中给出了一个有效的解决方案。

到此为止,我们对于viewstate的理解可以说是入门了。viewstate是用于:
1. 保存“某些”控件的状态的;
2. 所谓的“状态”是在页面后台(cs文件)中被修改的。

但这里仍然有很多问题值得我们探讨:
1. 为什么禁用viewstate之后,页面源代码中仍然有“<input type="hidden" name="__VIEWSTATE"……”?
2. 为什么是“某些”控件,不是所有的控件都有viewstate么?对了,viewstate是属于页面的还是控件的?
3. 能更深入的探寻viewstate的内部机制么?

今天先解释几个比较简单的问题吧。

1. <input type="hidden" name="__VIEWSTATE"……>里,存放的其实有两种数据:一是传统的viewstate,二是所谓的ControlState。而ControlState是不能被禁用的。所以,你总是能看到以上的声明。(我的理解,还不能证明,如有缪误,望指点!)

后面评论指出,这里的VIEWSTATE是<form runat="server"/>的结果。


2. viewstate是属于控件的,而页面本身其实就是一个控件。我曾在 用简单的代码测一测你是否真的了解:Asp.Net中的事件和委托的实现 一文中指出,这里贴出代码:




// 
      Summary:
 
     // 
          Represents an .aspx file, also known as a Web Forms page, requested from
 
     // 
          a server that hosts an ASP.NET Web application. 
     
 
         [DefaultEvent( 
     " 
     Load 
     " 
     )]
    [Designer( 
     " 
     Microsoft.VisualStudio.Web.WebForms.WebFormDesigner, Microsoft.VisualStudio.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
     " 
     ,  
     typeof 
     (IRootDesigner))]
    [DesignerCategory( 
     " 
     ASPXCodeBehind 
     " 
     )]
    [DesignerSerializer( 
     " 
     Microsoft.VisualStudio.Web.WebForms.WebFormCodeDomSerializer, Microsoft.VisualStudio.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
     " 
     ,  
     " 
     System.ComponentModel.Design.Serialization.TypeCodeDomSerializer, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 
     " 
     )]
    [ToolboxItem( 
     false 
     )]
 
     public 
      
     class 
      Page : TemplateControl, IHttpHandler





================================================================

后面的内容待我先整理一下,然后再发布,呵呵。


前几天做了一个网站。交给客户看(他水平可能也差不多半斤八两。也懂点HTML)
客户:"你那HTML里面怎么一大堆的看不懂的乱码啊?"
我:“那是程序生成的”
客户:“你技术也太差了,人家的就没有,你的为什么有,不行,这堆看不懂的东西一定要去掉,否则不结余款”

最后没办法,用nvelocity搞模板替换终于把那堆东西去掉了(跟dnt类似的解决方案).拿到了最后的一点钱!!现在还在郁闷。。。

   最后还是想请教一下,怎么样才能让viewstate东西无影无踪(排除MVC,这个我还不怎么懂)?



==============================================================================


禁掉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没有关系,但能澄清我们很多人的误解!包括我第一节里所犯的最大的错误,为了更清晰的演示,我修改了之前的代码:






< 
     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 
     >





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的解析、加密和压缩的内容。而且有详细的图片解说,相当值得一看。



如何让页面不生成viewState,而不是简单的禁用
http://bbs.csdn.net/topics/320245543

.net防止页面生成__VIEWSTATE



1.引入命名空间

using System.IO;
using System.Text.RegularExpressions;


2.重写Page类的Render方法:

protected override void Render(HtmlTextWriter writer)
    {
        StringWriter sw= new StringWriter();
        base.Render(new HtmlTextWriter(sw));//获取正常输出的html,包含__VIEWSTATE        string html = sw.ToString();
        html = Regex.Replace(html, @"<div[/s/S]*?__VIEWSTATE[/s/S]*?</div>", "");//过滤__VIEWSTATE
        writer.WriteLine(html.Trim());//输出过滤后的html    }


只需上面的操作即可将页面中冗余的__VIEWSTATE清除,你可以试试


不过要注意,清除了viewstate后,不影响页面布局,但是页面的许多事件都触发不了了,这也是一般不清除viewstate的原因,慎用。


在生成静态页面的时候用的较多。






转载于:https://blog.51cto.com/utalents/1394387


1.引入命名空间

using System.IO;
using System.Text.RegularExpressions;
2.重写Page类的Render方法:

    protected override void Render(HtmlTextWriter writer)
    {
        StringWriter sw= new StringWriter();
        base.Render(new HtmlTextWriter(sw));//获取正常输出的html,包含__VIEWSTATE        string html = sw.ToString();
        html = Regex.Replace(html, @"<div[/s/S]*?__VIEWSTATE[/s/S]*?</div>", "");//过滤__VIEWSTATE
        writer.WriteLine(html.Trim());//输出过滤后的html    }

只需上面的操作即可将页面中冗余的__VIEWSTATE清除,你可以试试


不过要注意,清除了viewstate后,不影响页面布局,但是页面的许多事件都触发不了了,这也是一般不清除viewstate的原因,慎用。


在生成静态页面的时候用的较多。