首页 > 编程 > .NET > 正文

小议优化ASP.NET应用性能之ViewState篇

2024-07-10 13:10:00
字体:
来源:转载
供稿:网友

   如果你有在ie中查看当前浏览页面html源代码的习惯,你也许常会看到类似以下的代码片断:

<input type="hidden" name="__viewstate" value="ddwtmzu5nzuymtq1o3q8o2w8atwwpjs+o2w8ddw7bdxppda+oz47bdx0pdtspg
……

  聪明的你一定会问,这是什么?有什么作用?它与本篇文章有何转折亲关系?各位看官,且听我慢慢道来。

  其实,这就是ms在asp.net应用viewstate技术的特征表现。为了页面能在postback后依然能读取服务器控件原有的状态数据,asp.net中使用了viewstate技术,而viewstate技术本质上是用一个默认名称为"__viewstate的hidden类型表单域来保存和传递数据(这些数据是经过了序列化后base64编码的字符串值,且是在方法page.savepagestatetopersistencemedium输出前保存、并由page.loadpagestatefrompersistencemedium加载)。虽然我们可以通过三种级别来轻松禁用掉这些数据的往返传递:

machine级 在machine.config中设置<pages enableviewstatemac='false' />
application级 在web applicatin的web.config中设置<pages enableviewstatemac='false' />
单页面级 在该页面中设置<%@page enableviewstatemac='false' %>或通过代码设置page.enableviewstatemac = false;
 
  可是,如果我们完全能通过禁用viewstate来解决数据传输负担而且不产生副作用的话,那ms的架构师们也不会傻到如此可爱的地步(可有可无的东东留它何用?),正因我们往往不能通过简单的禁用来解决这个传输负担问题,所以我们只能另辟路径使之在网络往返中传输量尽可能地小,于是,压缩成了我们的首选。只要我们重载page类的savepagestatetopersistencemedium()方法与loadpagestatefrompersistencemedium()方法,并在重载方法中对数据进行压缩与解压的处理即可。开源项目sharpziplib提供的类gzipinputstream与gzipoutputstream进入了我们的视野,为了方便,不妨写个类compressionhelper,代码如下:

 1using system.io;
 2using icsharpcode.sharpziplib.gzip;
 3
 4namespace ycweb.components
 5{
 6    /**//// <summary>
 7    /// summary description for compressionhelper.
 8    /// </summary>
 9    public class compressionhelper
10    {
11        public compressionhelper()
12        {
13            //
14            // todo: add constructor logic here
15            //
16        }
17
18        /**//// <summary>
19        /// 压缩数据
20        /// </summary>
21        /// <param name="data">待压缩的字节数组</param>
22        /// <returns>压缩后的字节数组</returns>
23        public static byte[] compressbyte(byte[] data)
24        {
25            memorystream ms = new memorystream();
26            stream s=new gzipoutputstream(ms);   
27            s.write( data, 0, data.length );
28            s.close();
29            return ms.toarray();   
30        }
31
32        /**//// <summary>
33        /// 解压数据
34        /// </summary>
35        /// <param name="data">待解压的字节数组</param>
36        /// <returns>解压出的字节数组</returns>
37        public static byte[] decompressbyte(byte[] data)
38        {
39            byte[] writedata = new byte[2048];
40            memorystream ms= new memorystream( data );
41            stream sm = new gzipinputstream(ms) as stream;
42            memorystream outstream = new memorystream();
43            while (true)
44            {
45                int size = sm.read(writedata,0, writedata.length );
46                if (size >0)
47                {
48                    outstream.write(writedata,0,size);
49                }
50                else
51                {
52                    break;
53                }
54            }
55            sm.close();
56            byte[] outarr = outstream.toarray();
57            outstream.close();
58            return outarr;   
59        }
60    }
61}

     然后我们在派生于类page的页面控制基类中重载方法loadpagestatefrompersistencemedium()与savepagestatetopersistencemedium(object viewstate),代码如下:

 1load & save viewstate data#region load & save viewstate data
 2        protected override object loadpagestatefrompersistencemedium()
 3        {
 4//从自己注册的隐藏域__smartviewstate中读取数据
 5            string viewstate = request.form["__smartviewstate"];
 6            byte[] bytes = convert.frombase64string(viewstate);
 7            //调用上面提供的静态方法compressionhelper.decompressbyte()来解压数据
 8            bytes = compressionhelper.decompressbyte(bytes);
 9            losformatter formatter = new losformatter();
10            return formatter.deserialize(convert.tobase64string(bytes));
11   
12        }
13
14        protected override void savepagestatetopersistencemedium(object viewstate)
15        {
16            losformatter formatter = new losformatter();
17            stringwriter writer = new stringwriter();
18            formatter.serialize(writer, viewstate);
19            string viewstatestring = writer.tostring();
20            byte[] bytes = convert.frombase64string(viewstatestring);
21            //调用上面提供的静态方法compressionhelper.compressbyte()来压缩数据
22            bytes = compressionhelper.compressbyte(bytes);
23           
24            //注册一个新的隐藏域__smartviewstate,你也可以自己定义
25            this.registerhiddenfield("__smartviewstate", convert.tobase64string(bytes));   
26        }
27#endregion

   经过以上处理,web输出页面中的源代码就是型如:

<input type="hidden" name="__smartviewstate" value="h4siaptponwa/81ce1pbwjb/ ……
<input type="hidden" name="__viewstate" value="" />

    原来的隐藏域"__viewstate"值为空,而取而代之的是我们自己注册的新的隐藏域"__smartviewstate"来存储了经过压缩后的字符串,这样以来,提速效果是明显的,结合我们的项目,象dg3g.com的首页原viewstate串值大约是28k,压缩后为7k,而acafa.com的首页原viewstate串值大约是43k,压缩后为8k。这样的处理还是比较令人满意的。当然,如果你觉得还不够彻底,你还可以把viewstate串存储在session中,不过这样做,对服务器内存的压力将陡增(尤其是访问量较大的时候),建议还是不要轻易使用,如果你web服务器内存有个10g、8g的,不妨试试。下面给出相关修改代码:

将上述loadpagestatefrompersistencemedium()方法体中的代码:
    string viewstate = request.form["__smartviewstate"];
修改为:
   string viewstate = session["__smartviewstate"].tostring();
同时,将上述savepagestatetopersistencemedium()体中的代码:
   this.registerhiddenfield("__smartviewstate", convert.tobase64string(bytes));
修改为:
   session["__smartviewstate"] = convert.tobase64string(bytes);

    末了,以上代码和方案均来自vs2003开发实践,对vs2005是否合适,本人不做任何承诺,不过如果你能从以上方案中有所收获,我将感到无比的高兴。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表