How to remove or compress your asp.net viewstate

2019-03-25 12:37发布

Just spent a lot of time exorcising asp.net's large (but understandably useful) viewstate from an app, and i think it's worth sharing how it's done.

Basically, i want this question to be open to all solutions for shrinking/compressing/removing viewstate.

8条回答
The star\"
2楼-- · 2019-03-25 13:14

Another better option, roll your own PageStatePersister. Here's mine, heavily inspired by 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楼-- · 2019-03-25 13:15

It's important at first to understand what the heck viewstate is and why you want it in the first place. After that, it's just a matter of being mindful of what the app is doing for you and remembering to attach the UseViewState="false" to all the elements that would normally use viewstate.

Now to remember why it's useful, you'll have a definite need to retrieve things more often manually.

A time and a place for all tools, yes?

查看更多
等我变得足够好
4楼-- · 2019-03-25 13:15

Completely get rid of it:

    protected override object LoadPageStateFromPersistenceMedium()
    {
        return null;
    }

    protected override void SavePageStateToPersistenceMedium(object viewState)
    {
    }
查看更多
Luminary・发光体
5楼-- · 2019-03-25 13:18

One method that we have used in my company is to remove most of it by removing the runat="server" calls. Then we use javascript, or a good javascript library like jQuery or Prototype, to populate the HTML elements using ajax calls to the server.

My boss did a lot of work with a website that had several megs of viewstate data. He used the above method and it "works great with no viewstate".

查看更多
不美不萌又怎样
6楼-- · 2019-03-25 13:24

First easy option, use the built-in SessionPageStatePersister class. What this does is keep the viewstate on the session on the server, rather than sending it to the client. However, it still sends a smaller viewstate down so isn't all roses:

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

This method shrunk a particularly large postback from 100k to 80k. Not great, but a good start.

查看更多
登录 后发表回答