如果你有在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是否合适,本人不做任何承诺,不过如果你能从以上方案中有所收获,我将感到无比的高兴。