【问题标题】:ASP.Net ViewState Compression: Should I bother?ASP.Net ViewState 压缩:我应该打扰吗?
【发布时间】:2010-10-25 16:14:21
【问题描述】:

所以基本上我正在开发一个试图针对手机进行优化的网站(这包括几乎所有支持浏览器的手机)由于该网站的性质,我希望它尽快加载。此时,我认为页面大小约为 30k 左右。

现在我正在使用视图状态,主要用于数据网格之类的东西,而不是我自己“保存”任何字段。

我已经看到很多像 (I swear not my blog) 这样的例子,考虑到 2.0,但没有任何处理 3.5,这让我想知道从那时起是否没有任何变化,或者压缩视图状态已经失宠。

问题是,我应该尝试压缩视图状态还是有更好的解决方案?

【问题讨论】:

    标签: asp.net .net-3.5 viewstate


    【解决方案1】:

    内存中数据的压缩和解压

    首先,我们需要一种方法来压缩和解压缩内存中的字节数组。我将这个简单的静态类放在一起,它公开了两种方法:压缩和解压缩。根据 MSDN,GZipStream 和 DeflateStream 这两个可用的类使用相同的算法,因此选择哪一个无关紧要。

    下面的代码很简单,不需要解释:

    
    
        using System.IO;
        using System.IO.Compression;
    
        public static class Compressor {
    
          public static byte[] Compress(byte[] data) {
            MemoryStream output = new MemoryStream();
            GZipStream gzip = new GZipStream(output, 
                              CompressionMode.Compress, true);
            gzip.Write(data, 0, data.Length);
            gzip.Close();
            return output.ToArray();
          }
    
          public static byte[] Decompress(byte[] data) {
            MemoryStream input = new MemoryStream();
            input.Write(data, 0, data.Length);
            input.Position = 0;
            GZipStream gzip = new GZipStream(input, 
                              CompressionMode.Decompress, true);
            MemoryStream output = new MemoryStream();
            byte[] buff = new byte[64];
            int read = -1;
            read = gzip.Read(buff, 0, buff.Length);
            while(read > 0) {
              output.Write(buff, 0, read);
              read = gzip.Read(buff, 0, buff.Length);
            }
            gzip.Close();
            return output.ToArray();
          }
        }
    
    

    您需要将此类保存在一个 .cs 文件中,并将其放在 ASP.NET 应用程序的 App_Code 目录中,确保它包含在正确的自定义命名空间中(如果您不指定任何命名空间,该类将在内置的 ASP 命名空间中可用)。

    压缩视图状态

    现在,我们可以实际压缩页面的 ViewState 了。为此,我们必须重写 LoadPageStateFromPersistenceMedium 和 SavePageStateToPersistenceMedium 这两个方法。该代码仅使用一个附加隐藏字段 __VSTATE 来存储压缩的 ViewState。如您所见,通过查看页面的 HTML,__VIEWSTATE 字段为空,而我们的 __VSTATE 字段包含压缩后的 ViewState,以 Base64 编码。让我们看看代码。

    
    
        public partial class MyPage : System.Web.UI.Page {
    
          protected override object LoadPageStateFromPersistenceMedium() {
            string viewState = Request.Form["__VSTATE"];
            byte[] bytes = Convert.FromBase64String(viewState);
            bytes = Compressor.Decompress(bytes);
            LosFormatter formatter = new LosFormatter();
            return formatter.Deserialize(Convert.ToBase64String(bytes));
          }
    
          protected override void SavePageStateToPersistenceMedium(object viewState) {
            LosFormatter formatter = new LosFormatter();
            StringWriter writer = new StringWriter();
            formatter.Serialize(writer, viewState);
            string viewStateString = writer.ToString();
            byte[] bytes = Convert.FromBase64String(viewStateString);
            bytes = Compressor.Compress(bytes);
            ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
          }
    
          // The rest of your code here...
    
        }
    
    

    在第一种方法中,我们只是从 Base64 解码,解压缩和反序列化 __VSTATE 的内容,并将其返回给运行时。在第二种方法中,我们执行相反的操作:在 Base64 中序列化、压缩和编码。然后将 Base64 字符串保存到 __VSTATE 隐藏字段中。 LosFormatter 对象执行序列化和反序列化任务。

    您可能还想创建一个新类,例如 CompressedPage,它继承自 System.Web.UI.Page,您在其中重写两个方法,然后从该类继承您的页面,例如 MyPage : CompressedPage。请记住,.NET 只有单一继承,通过这种方式,您“花费”了唯一的继承机会来使用 ViewState 压缩。另一方面,在每个类中重写这两个方法是浪费时间,因此您必须选择最适合您需要的方法。

    以上内容由 Dario Solera 在 codeproject 上首次发布。 http://www.codeproject.com/Articles/14733/ViewState-Compression

    【讨论】:

    • 您应该编辑它以格式化源代码,使其更清晰。
    • 我原以为在整个站点的 IIS 中启用 GZip 压缩会使仅 ViewState 的 GZip 压缩变得多余
    【解决方案2】:

    viewstate 的压缩只能减少 50% 左右。我提前了几步并使用了 ViewState 替换技术,其中 ViewState 被页面上的 GUID 替换。实际的 ViewState 数据保存在服务器本身的数据库中,客户端(浏览器)获取和提交的只是一个 62 字节的令牌。它减少了 200-300KB 的大 ViewState 到 62 字节。

    这里我已经写了如何用代码做到这一点.. http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/

    【讨论】:

    • 您的页面不再可用。
    【解决方案3】:

    我正在使用视图状态,主要用于数据网格之类的东西,而不是我自己“保存”任何字段。

    我最担心的是网格。您自己保存的字段往往是简单的变量,例如数据库 ID 或用户名。这些不会引起那么多问题,因为它们很小。整个网格可能包含大量数据,这就是您遇到麻烦的地方。

    请记住,用户必须将视图状态的内容从浏览器上传到服务器,然后在每次回发时将它们下载回来。如果你有一个 100Mbit 的网络服务器连接——比如网络表单更流行的公司局域网——那么 viewstate 就很棒。但是对于手机浏览器,许多用户可能会使用拨号上网,甚至更糟:按字节付费。在这种情况下,我会尝试尽可能关闭它,并且只在必要时启用它。

    【讨论】:

      【解决方案4】:

      我不认为在 2.0 中保存视图状态应该与在 3.5 中保存视图状态相同。减少视图状态的最好方法是不使用它,但这并不总是可行的。

      在这些情况下,您应该尝试权衡带宽与服务器上所需的额外处理时间。知道它是否值得的唯一方法是做它并衡量其影响。

      编辑

      我看到的另一个选项是将视图状态保存在服务器上。它可以保存在内存、数据库或磁盘中。取决于您的环境要求。这将是最大的带宽节省。

      Here's a code project article
      Looks like a good article

      【讨论】:

        【解决方案5】:

        拥有 ViewState 与拥有快速加载网页相反。为什么需要 ViewState?重新考虑您的设计并尽可能少地使用。我会将会话数据的负担放在服务器和/或数据库上,直到有理由将一些数据保留在 ViewState 中。

        【讨论】:

        • ViewState 有它的位置(然后是一些),但主张根本不使用它在 IMO 中太极端了。它对于存储您不希望存储在页面上的隐藏字段中的身份密钥(恶意用户可以篡改)非常宝贵。现在,如果您要在其中存储整个 DataSet 等,那么,是的,您需要重新考虑您的游戏计划。
        • AFAIK...我的许多客户向我寻求“很少有改进和性能改进”。在那种情况下,我不能去更改由其他程序员编写的会话管理的应用程序逻辑。我需要实施一些快速(如客户所说)修复以提高应用速度
        猜你喜欢
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多