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

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

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

第一个简单的选项,使用内置的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。 不是很好,但是一个好的开始。

切换到ASP.NET MVC ! 没有ViewState !

另一个更好的选择,滚动你自己的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: ///  /// 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. ///  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; if (recent == null) Page.Session[RecentViewStateQueue] = recent = new Queue(); 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()); } } 

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

现在要记住它为什么有用,你肯定需要手动更频繁地检索。

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

完全摆脱它:

  protected override object LoadPageStateFromPersistenceMedium() { return null; } protected override void SavePageStateToPersistenceMedium(object viewState) { } 

你可以试试吧 !

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

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

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

  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序列化的完整和完整的理解,请不要使用此代码

  

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

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

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