如何删除或压缩您的asp.net视图状态

时间:2011-01-17 22:56:03

标签: c# asp.net viewstate

花了很多时间从应用程序中驱逐asp.net的大型(但可以理解的有用)视图状态,我认为值得分享它是如何完成的。

基本上,我希望这个问题对缩小/压缩/删除视图状态的所有解决方案开放。

8 个答案:

答案 0 :(得分:7)

第一个简单选项,使用内置的SessionPageStatePersister类。这样做是将viewstate保留在服务器上的会话中,而不是将其发送到客户端。但是,它仍会向较小的视图状态发送,因此不是所有玫瑰:

using System.Web.UI;
... the following goes in your Page class (eg your .aspx.cs) ...
PageStatePersister pageStatePersister;
protected override PageStatePersister PageStatePersister
{
  get
  {
    // Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister
    // every call to this property, as it causes problems
    return pageStatePersister ?? (pageStatePersister = new SessionPageStatePersister(this));
  }
}

这种方法将一个特别大的回发从100k缩小到80k。不是很好,但是一个好的开始。

答案 1 :(得分:6)

切换到ASP.NET MVCNo ViewState

答案 2 :(得分:5)

另一个更好的选择,滚动您自己的PageStatePersister。这是我的,受http://aspalliance.com/72的启发:

using System.Web.UI;

... in your page class:

PageStatePersister pageStatePersister;
protected override PageStatePersister PageStatePersister
{
  get
  {
    // Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister
    // every call to this property, as it causes problems
    return pageStatePersister ?? (pageStatePersister = new BetterSessionPageStatePersister(this));
  }
}

... in your BetterSessionPageStatePersister.cs:

/// <summary>
/// This class allows the viewstate to be kept server-side, so that postbacks are as small as possible.
/// It is similar to the built-in 'SessionPageStatePersister', but it yields smaller postbacks,
/// because the SessionPageStatePersister still leaves some viewstate (possibly it leaves the controlstate)
/// in the postback.
/// </summary>
class BetterSessionPageStatePersister : PageStatePersister
{
  public BetterSessionPageStatePersister(Page page)
    : base(page)
  { }

  const string ViewStateFieldName = "__VIEWSTATEKEY";
  const string ViewStateKeyPrefix = "ViewState_";
  const string RecentViewStateQueue = "ViewStateQueue";
  const int RecentViewStateQueueMaxLength = 5;

  public override void Load()
  {
    // The cache key for this viewstate is stored in a hidden field, so grab it
    string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;

    // Grab the viewstate data using the key to look it up
    if (viewStateKey != null)
    {
      Pair p = (Pair)Page.Session[viewStateKey];
      ViewState = p.First;
      ControlState = p.Second;
    }
  }

  public override void Save()
  {
    // Give this viewstate a random key
    string viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString();

    // Store the view and control state
    Page.Session[viewStateKey] = new Pair(ViewState, ControlState);

    // Store the viewstate's key in a hidden field, so on postback we can grab it from the cache
    Page.ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);

    // Some tidying up: keep track of the X most recent viewstates for this user, and remove old ones
    var recent = Page.Session[RecentViewStateQueue] as Queue<string>;
    if (recent == null) Page.Session[RecentViewStateQueue] = recent = new Queue<string>();
    recent.Enqueue(viewStateKey); // Add this new one so it'll get removed later
    while (recent.Count > RecentViewStateQueueMaxLength) // If we've got lots in the queue, remove the old ones
      Page.Session.Remove(recent.Dequeue());
  }
}

答案 3 :(得分:2)

首先要了解最重要的观点是什么以及为什么首先需要它,这一点非常重要。在此之后,只需要注意应用程序正在为您做什么,并记住将UseViewState =“false”附加到通常使用viewstate的所有元素。

现在要记住它为什么有用,你需要更经常地手动检索。

所有工具的时间和地点,是吗?

答案 4 :(得分:2)

完全摆脱它:

    protected override object LoadPageStateFromPersistenceMedium()
    {
        return null;
    }

    protected override void SavePageStateToPersistenceMedium(object viewState)
    {
    }

答案 5 :(得分:1)

您可以尝试itit

答案 6 :(得分:1)

您可以通过一点点诡计,通过派生System.Web.Page并覆盖PageStatePersister属性来劫持页面状态的序列化:

    private PageStatePersister _pageStatePersister = null;
    protected override PageStatePersister PageStatePersister
    {
        get { return _pageStatePersister ?? (_pageStatePersister = new PersistState(this)); }
    }

完成此操作后,您可以从HiddenFieldPageStatePersister派生一个新实例,并从那里使用反射来更改持久性实现:

    class PersistState : HiddenFieldPageStatePersister, IStateFormatter
    {
        public PersistState(Page p) : base(p)
        {
            FieldInfo f = typeof(PageStatePersister).GetField("_stateFormatter", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField);
            f.SetValue(this, this);
        }

        object IStateFormatter.Deserialize(string serializedState)
        {
            BinaryFormatter f = new BinaryFormatter();
            using (GZipStream gz = new GZipStream(new MemoryStream(Convert.FromBase64String(serializedState)), CompressionMode.Decompress, false))
                return f.Deserialize(gz);                    
        }

        string IStateFormatter.Serialize(object state)
        {
            BinaryFormatter f = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress, true))
                    f.Serialize(gz, state);
                return Convert.ToBase64String(ms.ToArray());
            }
        }
    }

<强>提防

这仅是出于探索目的的示例。上述代码是安全风险,因为它不会对有效负载进行签名和加密,因此很容易被试图造成网站伤害的任何人攻击。

再次不要使用此代码,而不完全了解安全性,加密和.Net序列化。

</warning>

正如其他人所说,真正的问题是开始使用页面状态。对于大量使用页面状态的写得不好的ASP.NET应用程序而言,最简单的解决方案是站起来状态服务器并使用SessionPageStatePersister。

答案 7 :(得分:0)

我们公司使用的一种方法是删除runat="server"次调用,删除大部分内容。然后我们使用javascript,或者像jQuery或Prototype这样的好javascript库,使用对服务器的ajax调用来填充HTML元素。

我的老板在一个拥有几个视域状态数据的网站上做了很多工作。他使用了上述方法,并且“在没有视图状态下工作得很好”。