您的位置:首页 > 编程语言 > ASP

asp.net 2.0中通过压缩ViewState改善性能

2007-09-25 15:07 615 查看
原文地址:http://www.dotnetbips.com/articles/22d33d11-1a75-42c8-bbf6-ca1a345d3fcf.aspx
[原文源码下载]

[align=center][翻译]asp.net 2.0中通过压缩ViewState改善性能
[/align]

原文发布日期:2007.03.08
作者:Bipin Joshi
翻译:webabcd

介绍
开发人员经常担心他们web站点的性能。每一个开发者都想他们的web站点的性能是最优化的。影响你web站点性能的有很多因素,ViewState就是其中之一。本文我将给大家提供一个通过压缩ViewState来改善性能的方法。

什么是ViewState
虽然本文并不是专门来研究ViewState的,但我们还是简单的讨论一下吧。你如果看过web form生成的HTML代码的话,就会发现在一个名为__VIEWSTATE的隐藏域。聪明的ASP.NET会持久化这些控件的值到这个隐藏域中,这对于往返服务器的过程中保存控件的值是非常有用的。但是,此时ViewState会带来性能问题。因为ViewState要在服务端与客户端之间传输,所以会增加网络带宽的流量。

要减少ViewState的话,可以关闭ViewState,就是设置控件的EnableViewState属性,如果设置该属性为false则控件的ViewState将被关闭。但是,如果没有ViewState的话,控件状态持久化的工作就需要你自己来做了,这将是令人非常头痛的。还有另一种减少ViewState的方法就是本文将要介绍的方法,即在ViewState传输之前先压缩它,这样ViewState的数据将会大幅度减少。

在ASP.NET 1.x中如果我们要使用压缩功能的话需要自己写一些代码。而现在.NET 2.0提供了System.IO.Compression命名空间,将会使压缩功能的实现变得非常简单。System.IO.Compression命名空间的GZipStream类可以处理流的压缩和解压,注意,GZipStream只能以流的方式工作。GZipStream类不知专门压缩ViewState而设计的,所以我们为了实现ViewState的压缩和解压要自己写一些代码。

开发ViewStateHelper
我们首先用Visual Studio新建一个web站点,然后再App_Code文件夹中增加一个名为ViewStateHelper的类。类文件顶部要引入的命名空间如下


using System.IO;


using System.IO.Compression;

System.IO命名空间为我们提供了流的类,如MemoryStream。The System.IO.Compression命名空间为我们提供GZipStream类,它允许你呈现gzip格式的数据(RFC 1952)。

压缩数据
现在增加一个名为Compress()的方法如下


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();


}

这个Compress()静态方法接收一个字节数组类型的变量并压缩它,返回的是一个压缩后的字节数组。它首先实例话一个MemoryStream类,它用来呈现内存中的流。然后通过MemoryStream和压缩模式两个参数创建一个GZipStream对象。你可以用任何流类型来替换MemoryStream。被压缩的数据将写进这个流。GZipStream类的Write()方法会接收一个字节数组类型的变量,然后压缩它并写进流中(在我们的例子中是MEmoryStream)。写完之后GZipStream被关闭。最后,MemoryStream的ToArray()方法将转换流数据到字节数组中。

解压数据
为了解压数据,我们要增加另一个名为Decompress()的方法,其关键代码如下


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();


}

这个Decompress()静态方法接收一个已压缩的字节数组,返回一个解压后的字节数组。首先,它创建了一个MemoryStream对象,并将一个已压缩的字节数组写进去。然后这个流将作为参数提供给GZipStream的构造函数,注意此时的压缩模式为Decompress。解压后的数据也需要在某个地方保存,所以接下来创建的另一个MemoryStream对象就是作此用途。接着我们用一个while循环从GZipStream读取出解压后的数据,每一块都是1024字节。然后这个数据就被写进MemoryStream了。最后,GZipStream被关闭,解压后的内容作为一个字节数组被返回。

新建一个web form
现在打开一个web form,拖拽一个SqlDataSource控件到上面,配置它以使其可以从Northwind数据库中读取Customers表的记录。



拖拽一个GridView控件并设置它的DataSourceID属性为你刚才配置好的SqlDataSource控件的ID。确保运行这个web form是我们想要的结果,示例如下



定制ViewState的序列化和反序列化
你不用关心ViewState的序列化和反序列化,因为这些都是自动的。但是因为咱们需要压缩ViewState,所以需要定制它的序列化和反序列化。Page基类有两个虚拟方法,SavePageStateToPersistenceMedium()和LoadPageStateFromPersistenceMedium()。它们分别允许你定制ViewState的序列化和反序列化。

我们首先在web form的后置代码中重写SavePageStateToPersistenceMedium()方法。在这个方法中,你将压缩ViewState并存储它到隐藏域中。代码如下


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);


    byte[] compressedData = ViewStateHelper.Compress(data);


    string str = Convert.ToBase64String(compressedData);


    ClientScript.RegisterHiddenField("__MYVIEWSTATE", str);


}

SavePageStateToPersistenceMedium()方法接收一个ViewState对象。在该方法中创建一个LosFormatter对象,LosFormatter类允许你序列化和反序列化ViewState中的数据。LosFormatter类的Serialize()方法接收两个参数,分别是一个流和一个对象,结果是把这个对象序列化到这个流中。在我们的例子里,ViewState被序列化到了StringWriter里。StringWriter的ToString()方法返回一个字符串用于呈现ViewState数据。这个字符串是Base64格式的(在ASP.NET中就是这么存储到ViewState中的),我们需要把它转换成我们想要的格式。Convert类的FromBase64String()方法就可以做这个工作。FromBase64String()方法返回一个字节数组数据,然后使用我们的ViewStateHelper类的Compress()方法压缩它。然后使用Convert类的ToBase64String()方法把被压缩的数据转换成Base64格式。最后,我们用ClientScript的RegisterHiddenField()方法把这个已压缩的Base64格式的数据注册到一个名为__MYVIEWSTATE的隐藏域中。

这就是我们压缩ViewState的方法。另外还有一个同等重要的工作就是解压,我们通过重写LoadPageStateFromPersistenceMedium()方法来实现这样的功能,其代码如下


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);


}

这个方法首先读出__MYVIEWSTATE隐藏域的值,该值为Base64格式的被压缩ViewState。为了解压它,你的第一步工作仍然是把它转换为一个字节数组,我们通过Convert类的FromBase64String()方法来做。接下来我们用ViewStateHelper类的Decompress()方法解压数据。然后用Convert类的ToBase64String()方法再一次把解压后的数据转换为Base64格式的字符串。最后,LosFormatter对象反序列化解压后的ViewState

以上就是压缩和解压ViewState的全部内容。经过我对本例的实际测试发现未经压缩的ViewState大小为13,568字节,压缩后的ViewState大小为5,932字节。这对于改善性能是非常有用的,你说呢?

总结
从本文中你学到了如何通过压缩ViewState来改善你web站点的性能。GZipStream类提供了现成的把你的数据压缩成gzip格式的方法。被压缩的数据需要通过重写Page基类的SavePageStateToPersistenceMedium()方法保存。相似的,读取ViewState后我们需要通过重写LoadPageStateFromPersistenceMedium()来解压数据。

作者:Bipin Joshi
Email:http://www.dotnetbips.com/contact.aspx
简介:Bipin Joshi是DotNetBips.com的管理员。他是http://www.binaryintellect.com/的发起人,这个公司提供.NET framwork的培训和咨询服务。他在印度孟买为开发者提供培训。他也是微软的MVP(ASP.Net)和ASPInsiders的会员。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息