将ViewState移出页面?

时间:2008-09-07 02:47:33

标签: asp.net scalability viewstate

我们正试图尽可能减轻页面加载量。由于ViewState有时会膨胀到100k的页面,我很乐意完全消除它。

我很想听听其他人用来将ViewState移动到自定义提供程序的一些技巧。

那说了几句警告:

  • 我们平均每小时为2百万独立访问者提供服务。
  • 因此,数据库读取在性能方面一直是个严重问题,因此我不想将ViewState存储在数据库中。
  • 我们也是负载均衡器的幕后推手,因此任何解决方案都必须与用户在每次回发时从一台机器反弹到另一台机器。

想法?

15 个答案:

答案 0 :(得分:5)

你如何处理会话状态?有一个内置的“存储会话状态中的视图状态”提供程序。如果您将会话状态存储在某个快速,超出系统中,那么这可能是视图状态的最佳选择。

编辑:为此,请将以下代码添加到您的Page类/全局页面基类

    protected override PageStatePersister PageStatePersister {
        get { return new SessionPageStatePersister(this); }
    }

此外......对于大型视图状态来说,这绝不是一个完美的(甚至是好的)解决方案。与往常一样,尽可能减小视图状态的大小。但是,SessionPageStatePersister相对智能,避免每个会话存储无限数量的视图状态,并避免每个会话只存储一个视图状态。

答案 1 :(得分:2)

我已经测试了很多方法来从页面中删除视图状态的加载,以及在所有hacks和某些软件之间删除它真正可扩展的唯一方法是StrangeLoops As10000 appliance。透明,无需更改底层应用程序。

答案 2 :(得分:2)

作为previously stated,我过去曾使用数据库存储ViewState。虽然这对我们有用,但我们每小时的访问量不会接近200万。

无论是使用StrangeLoop产品还是其他产品,我认为硬件解决方案绝对是可行的方法。

答案 3 :(得分:2)

以下对我来说效果很好:

string vsid;

protected override object LoadPageStateFromPersistenceMedium()
{
  Pair vs = base.LoadPageStateFromPersistenceMedium() as Pair;
  vsid = vs.First as string;
  object result = Session[vsid];
  Session.Remove(vsid);
  return result;
}

protected override void SavePageStateToPersistenceMedium(object state)
{
  if (vsid == null)
  {
    vsid = Guid.NewGuid().ToString();
  }
  Session[vsid] = state;
  base.SavePageStateToPersistenceMedium(new Pair(vsid, null));
}

答案 4 :(得分:1)

你总是可以压缩ViewState,这样你就可以获得ViewState的好处而不会那么臃肿:

public partial class _Default : 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));
  }

  // ...

}

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

答案 5 :(得分:0)

由于典型的组织膨胀,请求新硬件需要很长时间,并且要求完全重新连接我们当前设置的硬件可能会受到工程部门的严重阻力。

我真的需要提出一个软件解决方案,因为这是我唯一可以控制的世界。

Yay for Enterprise :(

答案 6 :(得分:0)

我试图找到我过去研究的一些产品,就像StrangeLoops一样(但是基于软件)看起来他们全都已经破产了,这是我列表中唯一的东西还有ScaleOut,但它们专门用于会话状态缓存。

我理解向高级管理层出售硬件解决方案有多难,但至少让管理层接受听取硬件销售代表的意见总是一个好主意。我更倾向于使用一些能够为我提供即时解决方案的硬件,因为它允许我(或者花一些时间)来完成其他一些真正的工作。

我理解,这真的很糟糕,但替代方案是更改代码以进行优化,这可能比获取设备要花费更多。

如果您找到其他基于软件的解决方案,请告诉我。

答案 7 :(得分:0)

我要看看我是否可以想出一种方法来利用我们当前的State服务器来在内存中包含viewstate,我应该能够使用用户会话ID来保持机器之间的同步。

如果我想出一个好的解决方案,我会删除任何受IP保护的代码并将其公开使用。

答案 8 :(得分:0)

哦不,red tape。那么这将是一个很高的要求。您提到here您使用状态服务器来提供会话状态。你是如何进行这种设置的?也许你也可以在这里做类似的事情?

修改

Awh @Jonathan,you posted当我输入这个答案时。我认为走这条路可能很有希望。有一点是它肯定会占用大量内存。

@Mike我不认为将它存储在会话信息中是一个好主意,因为viewstate的内存密集度以及访问viewstate需要多少次。作为视图状态,SessionState的访问次数要少得多。我会将两者分开。

我认为最终的解决方案是将ViewState存储在客户端上,以及如何值得关注。使用Google Gears,现在可以实现。

答案 9 :(得分:0)

您是否考虑过您是否真的需要所有viewstate?例如,如果从数据库填充数据网格,则默认情况下,所有数据都将保存在viewstate中。但是,如果网格仅用于呈现数据,则不需要表单全部,因此没有视图状态。

当通过回发与用户进行某些交互时,您只需要viewstate,即使这样,实际的表单数据也可能足以重新创建视图。您可以有选择地禁用页面上控件的viewstate。

如果您实际上需要 100K的viewstate,那么您将拥有一个非常特殊的UI。如果您将viewstate减少到绝对必要的范围,那么它可能会变得最简单,最具可扩展性,可以将视图状态保留在页面中。

答案 10 :(得分:0)

我可能会在另一篇文章中找到一个简单的解决方案。这是一个简单的类,包含在您的应用程序和asp.net页面本身的几行代码中。如果将它与分布式缓存系统结合使用,可以节省大量的面团,因为视图状态很大且成本很高。微软的速度可能是附加此方法的好产品。如果你确实使用它并节省了大量的金钱,虽然我很想提一点。如果您不确定任何事情让我知道,我可以亲自与您交谈。

这是我的代码的链接。 link text

如果您关注扩展,那么使用会话令牌作为唯一标识符或在会话中存储状态或多或少保证在Web场方案中工作。

答案 11 :(得分:0)

将视图状态存储在会话对象中,并使用分布式缓存或状态服务来存储与我们服务器分离的会话,例如microsofts velocity。

答案 12 :(得分:0)

我知道这有点陈旧,但我已经使用鱿鱼和ecap在开源“虚拟设备”上工作了几天:

1。)gzip 2.)处理ssl 3.)在请求/响应上用令牌替换viewstate 4.)用于对象缓存的memcache

无论如何,它看起来很有希望。基本上它会坐在负载均衡器前面,应该真正帮助客户端性能。似乎也很难设置。

答案 13 :(得分:0)

我刚才在博客上发表了论文 - 解决方案是http://www.adverseconditionals.com/2008/06/storing-viewstate-in-memcached-ultimate.html

这使您可以通过使用自定义PageAdapter将ViewState提供程序更改为您选择的一个,而无需更改每个Page类。我将ViewState存储在memcached中。回想起来,我认为将它存储在数据库或磁盘上会更好 - 我们很快就填充了memcached。它是一种非常低摩擦的解决方案。

答案 14 :(得分:0)

无需购买或出售任何东西以消除视野状态膨胀。只需要扩展HiddenFieldPageStatePersister即可。 100-200KB的ViewState将保留在服务器上,而不会在页面上仅发送62byte令牌。

这是一篇关于如何做到这一点的详细文章:

http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/