关于asp.net:将ViewState移出页面吗?

关于asp.net:将ViewState移出页面吗?

Moving ViewState out of the page?

我们正在尝试尽可能减轻页面加载量。 由于ViewState有时最多可以放大100k页面,因此我希望完全消除它。

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

也就是说,一些警告:

  • 我们每小时平均为200万唯一身份访问者提供服务。
  • 因此,数据库读取一直是性能方面的严重问题,因此我不想将ViewState存储在数据库中。
  • 我们还在负载均衡器后面,因此任何解决方案都必须与用户一起在每次回发中从一台机器跳到另一台机器来工作。

有想法吗?


您如何处理会话状态?有一个内置的"在会话状态中存储视图状态"提供程序。如果将会话状态存储在proc系统之外的某些快速系统中,则这可能是viewstate的最佳选择。

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

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

同样,对于大视角状态,这绝对不是一个完美(甚至是好的)解决方案。与往常一样,请尽可能减小视图状态的大小。但是,SessionPageStatePersister相对智能,避免为每个会话存储无数个视图状态,并且避免每个会话仅存储一个视图状态。


以下对我来说非常有效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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));
}

如前所述,我过去曾使用该数据库存储ViewState。尽管这对我们有效,但每小时的独立访问者人数接近200万。

我认为,无论使用StrangeLoop产品还是其他产品,硬件解决方案绝对是必经之路。


我已经测试了许多方法来消除页面以及所有黑客与某些软件之间的视图状态负担,唯一真正可扩展的就是StrangeLoops As10000设备。透明,无需更改基础应用程序。


您始终可以压缩ViewState,以便在没有太多膨胀的情况下获得ViewState的好处:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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();
  }
}

无需买卖任何东西即可消除viewstate膨胀。只需扩展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/


我前一阵子在博客上-解决方案位于http://www.adverseconditionals.com/2008/06/storing-viewstate-in-memcached-ultimate.html

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


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

1.)gzip
2.)处理SSL
3.)根据请求/响应用令牌替换viewstate
4.)用于对象缓存的内存缓存

无论如何,它看起来很有前途。基本上,它应该位于负载平衡器的前面,并且应该确实有助于提高客户端的性能。似乎也很难设置。


将viewstate存储在会话对象中,并使用分布式缓存或状态服务存储与我们的服务器(例如Microsoft Velocity)分开的会话。


在另一篇文章中,我可能会为您提供一个简单的解决方案。这是一个简单的类,可以包含在您的应用程序中,并在asp.net页面本身中包含几行代码。如果将其与分布式缓存系统结合使用,则由于viewstate庞大且成本高昂,因此可以节省大量的面团。微软的速度也可能是附加此方法的好产品。如果您确实使用它并节省了一大笔钱,尽管我很想提一下。另外,如果您不确定任何事情,请告诉我,我可以亲自与您交谈。

这是我的代码的链接。连结文字

如果您担心扩展,则可以保证将会话令牌用作唯一标识符或将状态存储在会话中,或多或少可以保证在Web服务器场方案中工作。


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

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

如果您实际上需要100K的viewstate,则您有一个非常特殊的UI。如果将viewstate减少到绝对必要的程度,那么将viewstate保留在页面中可能是最简单,最具扩展性的。


哦,不,繁文tape节。好吧,这将是一个艰巨的任务。您在这里提到使用状态服务器来提供会话状态。您如何进行此设置?也许您也可以在这里做类似的事情?

编辑

啊@乔纳森(Jonathan),您在我输入此答案时发帖。我认为走这条路可能很有希望。一件事是,它肯定会占用大量内存。

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

我认为最终的解决方案将是在客户端上存储ViewState的方式,也许值得一看。使用Google Gears,现在可以实现这一点。


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

如果我想出一个好的解决方案,我将删除所有受IP保护的代码,并将其发布以供公众使用。


我试图找到我过去研究过的某些产品,这些产品的工作方式与StrangeLoops相同(但基于软件),看起来它们像是倒闭了,这是我列表中唯一剩下的就是ScaleOut,但是它们专用于会话状态缓存。

我知道向高级管理层出售硬件解决方案有多么困难,但是至少让管理层接受听取硬件销售代表的意见始终是一个好主意。我宁愿放置一些可以为我提供即时解决方案的硬件,因为它可以让我(或给我一些时间)完成其他实际工作。

我知道,这确实很糟糕,但是替代方法是更改??代码以进行优化,这可能比购买设备要花费更多。

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


由于典型的组织膨胀,要求新硬件接takes而来,而要求涉及我们现有设备的完整重新布线的硬件可能会受到工程部门的严重抵制。

我确实需要提出一个软件解决方案,因为那是我唯一可以控制的领域。

对企业来说是肯定的:(


推荐阅读