• 网页优化系列三:使用压缩后置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种缓存方式

    欢迎添加我的公众号一起深入探讨技术手艺人的那些事!

    如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!
      

  • 相关阅读:
    Oracle常见授权与回收权限——grant和revoke
    数据库之笛卡尔积
    hdu 2032 一维数组实现杨辉三角
    poj3071之概率DP
    冒泡排序及两种优化方式
    Non-ASCII character &#39;xe8&#39; in file xxx.py on line 8, but no encoding declared
    编写shell脚本获取本机的网络地址。&#160; 比方:本机的ip地址是:192.168.100.2/255.255.255.0,那么它的网络地址是&#160;192.168.100.1/255.255.255.
    移动站点性能优化
    Math类概述及其成员方法
    java中StringBuilder、StringBuffer、String类之间的关系
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/2282325.html
Copyright © 2020-2023  润新知