网页优化系列三:使用压缩后置viewstate

  Asp.net中的服务器控件都启用了viewstate,虽然方便了开发人员,但页面大小及性能上确实有所影响,对于无需viewstate的控件及页面可以直接把控件或页面的viewstate禁用掉,但对于必须的viewstate我们可以采取另一种方式来处理——压缩。判断是否需要viewstate压缩准则是,内网系统不必考虑压缩(网速够快还闲着没事消耗服务器CPU资源干啥啊。。。),对外系统根据viewstate长度选择性进行压缩(当viewstate长度大于某个值时进行压缩,太短还压缩得不偿失哦。。。)

  好了,下面具体展开吧!

  一,viewstate压缩:

  页面的生存周期里保存viewstate的方法为SavePageStateToPersistenceMedium方法,所以重写这个方法就ok了。

 1  protected override void SavePageStateToPersistenceMedium(object state)
 2     {
 3         StringBuilder sb = new StringBuilder();
 4         TextWriter tw = new StringWriter(sb);
 5         LosFormatter lf = new LosFormatter();
 6         lf.Serialize(tw, state);
 7         tw.Flush();
 8         tw.Close();
 9         tw.Dispose();
10         bool useZip = false;
11         string finalStr = sb.ToString();
12         if (sb.Length >= 1096)
13         {
14             useZip = true;
15             byte[] bytes = Compress(Convert.FromBase64String(finalStr));
16             finalStr = Convert.ToBase64String(bytes);
17         }
18 
19         ClientScript.RegisterHiddenField("_MyViewState", finalStr);
20         ClientScript.RegisterHiddenField("_UseZip", (useZip?"T":"F"));
21     }
22 
23    private byte[] Compress(byte[] data)
24     {
25         MemoryStream ms = new MemoryStream();
26         GZipStream gzip = new GZipStream(ms, CompressionMode.Compress);
27         gzip.Write(data, 0, data.Length);
28         gzip.Flush();
29         gzip.Close();
30         gzip.Dispose();
31 
32         byte[] bytes = ms.ToArray();
33         ms.Close();
34         ms.Dispose();
35 
36         return bytes;
37     }

1.传入的参数state就是页面所有的viewstate集合对象,默认时该对象是经过序列化后保存到__ViewState的隐藏控件中的。所以要用LosFormatter对象将将state对象序列化,此时得到的序列化字符串是68位的数为基来编码的。

2.1096表示当viewstate长度大于1096时就压缩,否则就原封不动。

3..net有的System.IO.Compression中有两种压缩方式,这里选用GZip,也可以用其他更好的压缩算法的方法,压出效果就好^_^!

4.压缩完后恢复成以68位的数为基的编码字符串保存到__MyViewState的隐藏控件中,注意不能用回默认的__ViewState保存,否则会出错。

搞定压缩部分,当然都解压部分啦,回传时通过LoadPageStateFromPersistenceMedium方法获取viewstate,所以继续重写吧

 1   protected override object LoadPageStateFromPersistenceMedium()
 2     {
 3         string myViewState = Request.Form["_MyViewState"];
 4         bool useZip = (Request.Form["_UseZip"].Equals("T")?true:false);
 5         LosFormatter lf = new LosFormatter();
 6         if (useZip)
 7         {
 8             byte[] bytes = Convert.FromBase64String(myViewState);
 9             bytes = Decompress(bytes);
10 
11             return lf.Deserialize(Convert.ToBase64String(bytes));
12         }
13         else
14         {
15             return lf.Deserialize(myViewState);
16         }
17     }
18   private byte[] Decompress(byte[] data)
19     {
20         MemoryStream ms = new MemoryStream(data);
21         GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress);
22         byte[] resultByte = null;
23         int count = 1;
24         MemoryStream resultMs = new MemoryStream();
25         while (count >= 1)
26         {
27             resultByte = new byte[1024];
28             count = gzip.Read(resultByte, 0, 1024);
29             resultMs.Write(resultByte, 0, count);
30         }
31         resultByte = resultMs.ToArray();
32         resultMs.Close();
33         resultMs.Dispose();
34         gzip.Close();
35         gzip.Dispose();
36         ms.Close();
37         ms.Dispose();
38 
39         return resultByte;
40     }

1.从__MyViewState中获取viewstate字符串,然后是解压、反序列,得到之前保存的ViewState对象。

这样ViewState的压缩就KO了。当然Asp.net还可以将ViewState保存到Session里面,设置一下就好了,非常方便,也免得自己来处理多页面出现的ViewState覆盖问题。

  二,后置ViewState(2011.12.12校正)

viewstate默认是保存到页面的开头部分,如果长度过大会对搜索引擎爬该网站有一定的影响,可以通过把ViewState放置到页面最后的方式优化,后置viewstate还有一个好处就是页面会出来快一点哦。

 1  protected override void Render(HtmlTextWriter writer)
 2     {
 3         StringWriter sw = new StringWriter();
 4         HtmlTextWriter htw = new HtmlTextWriter(sw);
 5         base.Render(htw);
 6         htw.Flush();
 7         htw.Close();
 8         htw.Dispose();
 9         StringBuilder resulteHtml = new StringBuilder(sw.ToString());
10         sw.Close();
11         sw.Dispose();
12 
13         Regex reg = new Regex("<input type=\"hidden\" name=\"_MyViewState\" id=\"_MyViewState\" .* />");
14         string myViewState = reg.Match(resulteHtml.ToString()).Value;
       if(!string.IsNullOrEmpty(myViewState))
      {
15           resulteHtml.Replace(myViewState, string.Empty);
16         resulteHtml.Append(myViewState);//不能把自定义隐藏控件放在页面的最后
         int formEndTag_index=resulteHtml.ToString().IndexOf("</form>");
             resulteHtml.Insert(forEndTag_index,myViewState);
17           reg = new Regex("<input type=\"hidden\" name=\"_UseZip\" id=\"_UseZip\" .* />");
18           myViewState = reg.Match(resulteHtml.ToString()).Value;
19           resulteHtml.Replace(myViewState, string.Empty);
20         resulteHtml.Append(myViewState);//不能把自定义隐藏控件放在页面的最后
         formEndTag_index=resulteHtml.ToString().IndexOf("</form>");
             resulteHtml.Insert(forEndTag_index,myViewState);
       }

21         Response.Write(resulteHtml.ToString());
22     }

Render是页面发送给用户前最后留给我们发挥的地方了(除了自定义HttpModule啦),base.Render()会将页面控件所生成的html代码输入到HtmlTextWriter

对象中,通过它就可以得到页面最终的html代码了,接着就用正则表达式获取viewstate部分,并移动到html代码的最后,然后直接输出到响应流中,至于重写方

法中的参数,就当作路人甲乙丙吧。

2011.12.12校正部分:

   1.若直接把自定义隐藏控件保存到html代码末尾结果为:....</form><input type="hidden" id="_MyViewState" name="_MyViewState"... ,

当postback时在LoadPageStateFromPersistenceMedium时因隐藏控件在form之外,所以无法用form["参数命"]来获取。因此要将自定义隐藏控件放在</form

>标签之前。

2.判断myViewState是否为空字符串目的是,当使用ajax.net时render所得到的内容并不包含之前自定义的隐藏控件,防止string.replace中oldvalue为空时抛出异常。

  3.当页面使用ajax.net时并且使用该基类对viewstate作处理,会出现UpdatePanel控件内的更新、删除操作失效,原因暂时不清楚,大家有没有好方法啊??请告诉我吧!~~

下一篇:网页优化系列四:Asp.Net的5种缓存方式

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏偏前端工程师的驿站

网页优化系列三:使用压缩后置viewstate

  Asp.net中的服务器控件都启用了viewstate,虽然方便了开发人员,但页面大小及性能上确实有所影响,对于无需viewstate的控件及页面可以直接把...

21860
来自专栏Golang语言社区

用golang写的golang解析json数据的包

gojson是快速解析json数据的一个golang包,你使用它可以快速的查找json内的数据 安装 go get github.com/widuu/gojs...

364110
来自专栏Kiba518

C#线程安全使用(四)

这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来。

9330
来自专栏岑玉海

C#向excel中写入数据的三种方式

第一种:将DataGrid中的数据以流的形式写到excel中,格式以html的形式存在             Response.Clear();       ...

32440
来自专栏逸鹏说道

weiapi2.2 HelpPage自动生成接口说明文档和接口测试功能

在开发Webapi项目时每写完一个方法时,是不是需要添加相应的功能说明和测试案例呢?为了更简单方便的写说明接口文档和接口测试HelpPage提供了一个方便的途径...

30170
来自专栏Golang语言社区

Go语言test之类方法测试

Go语言提供了完善的单元测试支持,开发人员可以方便的编写测试代码,保证自己代码的质量。在目前的例子中,一般看到都是普通函数的例子。下面我将举类方法的测试例子来展...

379100
来自专栏跟着阿笨一起玩NET

如何让DevExpress TreeList的每个结点高亮显示?

原文地址:http://www.devexpresscn.com/devResources/page-18-78.html

19920
来自专栏GIS讲堂

一个GISER 6.7的祝福

一年一度的高考今天开始了,回想10年前,那是我第一次高考;10年后,作为一个GISER,在此给大家献上一个GISER的祝福,祝愿各位考生:考神附体,考完报考GI...

15340
来自专栏DOTNET

asp.net web api 版本控制

版本控制 版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通...

62160
来自专栏函数式编程语言及工具

FunDA(16)- 示范:整合并行运算 - total parallelism solution

   在对上两篇讨论中我们介绍了并行运算的两种体现方式:并行构建数据源及并行运算用户自定义函数。我们分别对这两部分进行了示范。本篇我准备示范把这两种情况集成一体...

207100

扫码关注云+社区

领取腾讯云代金券