有关视图状态(ViewState)的一些问题

ASP.NET的ViewState是一个毁誉参半的设计。虽然很少有人真的讲清楚里面存的是什么东西,而且它到底将怎么影响我们的开发。但是大家目前的几点共识如下

1. 能不用它的时候就不用,以免降低性能。

要关闭它有三种方式

1.1 通过在web.config中将所有页面的视图状态都关闭掉

1.2 在某个特定页面中将其关闭

1.3 在某个特定控件上将其关闭

2. 如果非得用它,但又顾忌到性能和网络流量。那么可以选择压缩它。下面这个文档有详细的介绍。

http://www.cnblogs.com/webabcd/archive/2008/08/21/672587.html

 

大致的代码如下。主要重写了两个方法,SavePageStateToPersistenceMedium和LoadPageStateFromPersistenceMedium

【注意】这里既然是可以控制保存和加载行为,那么从道理上说,也可以把这些状态保存到其他地方,例如Session中。(手机页面通常这么做)

【注意】同样的道理,这里也可以进行加密和解密操作

protected override void SavePageStateToPersistenceMedium(object state) //这里传过来的参数就是那些视图状态值
{
    LosFormatter formatter = new LosFormatter();
    StringWriter writer = new StringWriter();
    formatter.Serialize(writer, state);
string viewState = writer.ToString();
byte[] data = Convert.FromBase64String(viewState);//一般都是用BASE64进行编码
byte[] compressedData = ViewStateHelper.Compress(data);
string str = Convert.ToBase64String(compressedData);
    ClientScript.RegisterHiddenField("__MYVIEWSTATE", str);//目前还是放在页面里面。只不过是另外一个隐藏域而已。
}

protected override object LoadPageStateFromPersistenceMedium()
{
string viewstate = Request.Form["__MYVIEWSTATE"];
byte[] data = Convert.FromBase64String(viewstate);
byte[] uncompressedData =
    ViewStateHelper.Decompress(data);
string str = Convert.ToBase64String(uncompressedData);
    LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(str);
}

为了方便,这里编写了一个用来压缩和解压缩的帮助类(ViewStateHelper)

public static byte[] Compress(byte[] data)
{
    MemoryStream ms = new MemoryStream();
    GZipStream stream = new GZipStream(ms, CompressionMode.Compress);
    stream.Write(data, 0, data.Length);
    stream.Close();
return ms.ToArray();
}

public static byte[] Decompress(byte[] data)
{
    MemoryStream ms = new MemoryStream();
    ms.Write(data, 0, data.Length);
    ms.Position = 0;
    GZipStream stream = new GZipStream(ms, CompressionMode.Decompress);
    MemoryStream temp = new MemoryStream();
byte[] buffer = new byte[1024];
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
{
break;
        }
else
{
            temp.Write(buffer, 0, buffer.Length);
        }
    }
    stream.Close();
return temp.ToArray();
}

 

3. 除了可以压缩和加密,还有朋友提出,为了提高页面对于搜索引擎的友好性,应该将ViewState从表单的顶部移动到底部。这是一个很有意思的想法,下面这个文章讲述了大致怎么做

http://blog.csdn.net/lee576/archive/2008/11/01/3200258.aspx

 

这个代码的工作原理其实比较简单,它是重写了页面的Render方法,并且强制将那个视图状态的input移动到了底部。

 

//ViewState的Html标记的正则表达式
       private static readonly Regex viewStateRegex = new Regex(@"(<input type=""hidden"" name=""__VIEWSTATE"" id=""__VIEWSTATE"" value=""/w(.*)"" />)", RegexOptions.Multiline | RegexOptions.Compiled);
       //</form>标记的正则表达式
       private static readonly Regex endFormRegex = new Regex(@"</form>", RegexOptions.Multiline | RegexOptions.Compiled);
       protected override void Render(HtmlTextWriter writer)
       {
           System.IO.StringWriter stringWriter = new System.IO.StringWriter();
           HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
           base.Render(htmlWriter);

           string html = stringWriter.ToString();
           Match viewStateMatch = viewStateRegex.Match(html);

           string viewStateString = viewStateMatch.Captures[0].Value;//找出ViewState的Html标记
           html = html.Remove(viewStateMatch.Index, viewStateMatch.Length);//替换掉ViewState的html标记

           Match endFormMath = endFormRegex.Match(html, viewStateMatch.Index);
           html = html.Insert(endFormMath.Index, viewStateString);//将ViewState的Html标记插入到</form>标记之前
           writer.Write(html);

       }

4. ViewState对象

ViewState不光是控件或者页面的一个属性,它也是一个特殊的API。我们可以通过ViewState[“VarName”]=value这种方式对其进行读写。但这个功能显然也是受到了页面级别的那个EnableViewState开关的控制。

 

5. 控件状态

因为ViewState可以被禁用,但是如果服务器控件需要保留自己的一些值,那么就可能会用到控件状态。有兴趣的朋友可以参考我另外一篇博客

http://www.cnblogs.com/chenxizhang/archive/2009/04/02/1427827.html

posted @ 2009-04-02 16:30  陈希章  阅读(810)  评论(1编辑  收藏  举报