花了很多时间从应用程序中驱逐asp.net的大型(但可以理解的有用)视图状态,我认为值得分享它是如何完成的。
基本上,我希望这个问题对缩小/压缩/删除视图状态的所有解决方案开放。
答案 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 MVC! No 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)
答案 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元素。
我的老板在一个拥有几个视域状态数据的网站上做了很多工作。他使用了上述方法,并且“在没有视图状态下工作得很好”。