昨晚上写了一篇"压缩ASP.NET中的ViewState"的文章,大家都对这种方式是否会带来性能上消耗的问题比较关心.
有一点是肯定的,压缩ViewState的减少网络带宽的占用,肯定会对性能有影响.

我作了一个小小的测试.先后用同一个页面加密和不加密的情况下,刷新页面观测w3wp.exe的CPU占用情况.此页面的ViewState大小为3.996 Bytes

w3wp.exe 以下是每次刷新的时CPU的情况

05 03 05 03 06 05 05 08 03 05 03 不加密,平均是 4.6
05 05 06 05 05 03 08 02 03 05 06 加密,平均是5.3


 

今天双鱼座网友的留言写的挺好的:
我觉得真的很在乎服务器开销的话,建议修改一下方法,如果序列化后的长度大于某个值才压缩,然后在压缩码的最前面加上某个标记以便载入时判断是否为压缩的数据。
有些在使用TreeView和DataGrid的时候,数据量是很大的,达到数百K之巨。但是另外一些时候数据量很小,再压缩就非常不合算了。
另外,如果系统是面向internet的应用应该以网络带宽负荷为优先;局域网内的应用则应以服务器CPU负荷为优先,不一而论。


 

晚上借用加班的时间按双鱼座网友的方案对代码进行了一些改动,可以设置当ViewState为多大时才启用压缩,和压缩比率的设置.

修改后的源码如下:

using System;
using System.Web.UI;
using System.IO;
using ICSharpCode.SharpZipLib.Zip.Compression;

namespace MSPlus.Web.UI
{
    
/// <summary>
    
/// PageClass 的摘要说明。
    
/// </summary>

    public class Page : System.Web.UI.Page
    
{
        
/// <summary>
        
/// 设定序列化后的字符串长度为多少后启用压缩
        
/// </summary>

        private static Int32 LimitLength = 1096;

        
/// <summary>
        
/// 设定压缩比率,压缩比率越高性消耗也将增大
        
/// </summary>

        private static Int32 ZipLevel    = ICSharpCode.SharpZipLib.Zip.Compression.Deflater.BEST_COMPRESSION;

        
/// <summary>
        
/// 重写保存页的所有视图状态信息
        
/// </summary>
        
/// <param name="pViewState">要在其中存储视图状态信息的对象</param>

        protected override void SavePageStateToPersistenceMedium(Object pViewState)
        
{
            
//实现一个用于将信息写入字符串的 TextWriter
            StringWriter mWriter    = new StringWriter();

            
//序列化 Web 窗体页的视图状态
            LosFormatter mFormat    = new LosFormatter();

            
//将有限对象序列化 (LOS) 格式化的对象转换为视图状态值
            mFormat.Serialize(mWriter, pViewState);

            
//将序列化对象转成Base64字符串
            String vStateStr = mWriter.ToString();

            
//设置是否启用了加密方式,默认情况下为不启用
            Boolean mUseZip = false;

            
//判断序列化对象的字符串长度是否超出定义的长度界限
            if(vStateStr.Length > LimitLength)
            
{
                
//对于长度超出阶线的进行加密,同时将状态设为加密方式
                mUseZip = true;

                Byte[] pBytes 
= Compress(vStateStr);

                
//将字节数组转换为Base64字符串
                vStateStr = System.Convert.ToBase64String(pBytes); 
            }


            
//注册在页面储存ViewState状态的隐藏文本框,并将内容写入这个文本框
            RegisterHiddenField("__MSPVSTATE", vStateStr);

            
//注册在页面储存是否启用压缩状态的文本框,并将启用状态写入这个文本框
            RegisterHiddenField("__MSPVSTATE_ZIP", mUseZip.ToString().ToLower());
        }


        
/// <summary>
        
/// 对字符串进行压缩
        
/// </summary>
        
/// <param name="pViewState">ViewState字符串</param>
        
/// <returns>返回流的字节数组</returns>

        public static Byte[] Compress(String pViewState) 
        

            
//将存储状态的Base64字串转换为字节数组
            Byte[] pBytes = System.Convert.FromBase64String(pViewState);

            
//创建支持内存存储的流
            MemoryStream mMemory = new MemoryStream();

            Deflater mDeflater 
= new Deflater(ZipLevel);
            ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream mStream 
= new ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream(mMemory,mDeflater,131072);

            mStream.Write(pBytes,
0,pBytes.Length);
            mStream.Close();

            
return mMemory.ToArray();
        }
 

        
/// <summary>
        
/// 重写将所有保存的视图状态信息加载到页面对象
        
/// </summary>
        
/// <returns>保存的视图状态</returns>

        protected override Object LoadPageStateFromPersistenceMedium()
        
{
            
//使用Request方法获取序列化的ViewState字符串
            String mViewState        = this.Request.Form.Get("__MSPVSTATE");
            
//使和Request方法获取当前的ViewState是否启用了压缩
            String mViewStateZip    = this.Request.Form.Get("__MSPVSTATE_ZIP");

            Byte[] pBytes;

            
if(mViewStateZip == "true")
            
{
                pBytes 
= DeCompress(mViewState);
            }

            
else
            
{
                
//将ViewState的Base64字符串转换成字节
                pBytes = System.Convert.FromBase64String(mViewState);
            }


            
//序列化 Web 窗体页的视图状态
            LosFormatter mFormat = new LosFormatter();

            
//将指定的视图状态值转换为有限对象序列化 (LOS) 格式化的对象
            return mFormat.Deserialize(System.Convert.ToBase64String(pBytes));
        }


        
/// <summary>
        
/// 解压缩ViewState字符串
        
/// </summary>
        
/// <param name="pViewState">ViewState字符串</param>
        
/// <returns>返回流的字节数组</returns>

        public static Byte[] DeCompress(String pViewState) 
        

            
//将Base64字符串转换为字节数组
            Byte[] pBytes = System.Convert.FromBase64String(pViewState);

            ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream mStream 
= new ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(new MemoryStream(pBytes));
            
            
//创建支持内存存储的流
            MemoryStream mMemory = new MemoryStream();
            Int32 mSize;

            Byte[] mWriteData 
= new Byte[4096];

            
while(true)
            
{
                mSize 
= mStream.Read(mWriteData, 0, mWriteData.Length);
                
if (mSize > 0)
                
{
                    mMemory.Write(mWriteData, 
0, mSize);
                }

                
else
                
{
                     
break;
                }

            }


            mStream.Close();
            
return mMemory.ToArray();
        }
 

    }

}


其中压缩组件用的是SharpZipLib
posted on 2005-07-28 19:55 Mack.Z 阅读(4059) 评论(18)  编辑 收藏 引用 网摘 所属分类: MSPlus Web.UI

评论

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 20:16 exhjw
good.这么快就改过了呀  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 21:14 双鱼座
强人!  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 21:19 exhjw
TO:双鱼座

从来都没有想到过压缩viewstate来减轻带宽负荷,Mack.Z 做到了

而设置当ViewState为多大时才启用压缩,和压缩比率则此方案就更加优美了,你们俩都是强人!  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 21:39 Lostinet
压缩VIEWSTATE,还不如压缩HTTP内容.
可以考虑把VIEWSTATE保存到磁盘中。
  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 22:02 Sharper代码人生
保存在磁盘, 与Session关联  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-28 23:09 Goodspeed
其实是可以用Http压缩的来完成的

http://www.cnblogs.com/dudu/archive/2004/12/12/76085.html  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 00:02 Mack.Z
Http压缩方式,只对客户端为IE的浏览器才行!Http的压缩一般用于HTML等这种相对静态的文件,对于ASPX这类时刻变化的页面好像并不太合适  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 00:10 SK
保存在磁盘, 与Session关联 ....
这个不可以行.第一存磁盘读写太慢,第二放SESSION浪费内存  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 10:56 牙神幻十郎
觉的保存到磁盘不错,不过需要写个线程来清理服务器上的文件,否则增长很快的.  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 11:47 Sharper代码人生
将 ViewState数据保存在磁盘上,
有这样的软件产品.
  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 11:47 Sharper代码人生
将 ViewState数据保存在磁盘上,
有这样的软件产品.
  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-29 14:16 zhumk
to Mack.Z
“Http压缩方式,只对客户端为IE的浏览器才行!”
对于给出的意见我不赞同,据我所知,HTTP压缩使用的是业界标准的压缩方法如GZIP,WEB服务器会根据客户段浏览器是否支持压缩来选择新的返回给客户端,而且现在并不是只有IE才支持HTTP压缩的。

支持将ViewState保存到磁盘或者数据库中,不传送给客户端。
  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-07-30 13:10 微软迷
靠.这都能想到,强啊  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-09-14 17:21 脉搏
有一个问题希望能得到您的帮助:
我定义了一个复合控件,其中含一Label和一TextBox
定义了一个属性
public FontInfo CaptionFont
{
get
{
this.EnsureChildControls();
return elb.Font;
}
}
其中elb为子控件Label,我想在引用控件的时候通过设置这个属性来设置子控件
Label的字体样式,这个方法在设计时没有问题,字体会随着设置变化而变化,但实际
运行时,通过该属性设置的样式根本不起作用。不知道是什么原因;如果我想达到我想要的效果,我该如何作呢?
我在这个控件中重写了RenderContents方法,填加了一个表格,在td中通过RendControl方法填加的子控件Label
writer.RenderBeginTag(HtmlTextWriterTag.Td);
elb.RenderControl(writer);
writer.RenderEndTag();
不知道这样是不是会有影响。
试用用override FontInfo Font来重写Font属性,这样会实现我要的结果,但只能实现其中一个子控件,其他无法实现,希望您帮个忙给我个解决方案。谢谢!!  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-09-23 09:10 浪子
出现一个大问题:

从客户端(__MSPVSTATE="...IEEB/8DBI0Ong==")中检测到有潜在危险的 Request.Form 值。
说明: 请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止。该值可能指示危及应用程序安全的尝试,如跨站点的脚本攻击。通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证。但是,在这种情况下,强烈建议应用程序显式检查所有输入。

异常详细信息: System.Web.HttpRequestValidationException: 从客户端(__MSPVSTATE="...IEEB/8DBI0Ong==")中检测到有潜在危险的 Request.Form 值。

压缩后的值如下:

<input type="hidden" name="__MSPVSTATE" value="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" />  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2005-09-27 11:44 M
在Web.Config增加这句
<system.web>
<pages validateRequest="false" />
</system.web>
  回复  更多评论
  

# re: 压缩ASP.NET中的ViewState的改进方法 2006-09-04 23:13 Wintle
借用了,谢谢:)  回复  更多评论
  

# MSPlus.Web.UI.WebControls.MSMenu的属性ImagePath 2006-11-09 17:28 miacaoren
MSPlus.Web.UI.WebControls.MSMenu的属性ImagePath所指的路径怎么不能改到其它路径呢?谢谢。  回复  更多评论