对ViewState的误解有可能导致
- 泄漏敏感数据
- ViewState攻击
- 性能低下
- 可扩展性低下
ViewState做些什么
- 根据Key为每个控件储值
- 跟踪ViewState值 初始状态(initial state)的改变
- 串行化和并行化存储的数据并存入到一个隐藏字段
- 在回发期间自动重建ViewState
ViewState不做什么
- 自动持久化类中变量的状态
- 对于回发请求,在页面加载的过程中记录状态信息
- 在每次请求过程中使系统不重新填充数据
- ViewState不为所有的控件服务
- 为你煮咖啡
ViewState核心
1.ViewState储值
ViewState只是一个属性名,它的类型是StateBag。ViewState属性是诸如Page、用户控件(user control)、服务器控件等从System.Web.UI.Control这个基类继承来的。ViewState在Control类中的源码
protected virtual StateBag ViewState { get; }
为了维持状态的连续性,或者说提供类似Winform一样的交互体验,Asp.Net服务器控件中的属性储值方式类似下面的代码。
public string Text {
get {
return ViewState["Text"] == null ?
"Default Value!" :
(string)ViewState["Text"];
}
set { ViewState["Text"] = value; }
}
注意当ViewState["Text"]为null时,从Text取到的值将为初始值而非null。所以Text = null这样的赋值将导致重设Text为初值。
2.ViewState跟踪变化(Changes)
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns false
stateBag.TrackViewState();
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns true
只有StateBag.TrackViewState()被调用以后,对StateBag中某个项目的赋值才会引发这个项被标记为脏(dirty)。在页面的生命周期中,TrackViewState( )在OnInit( )阶段被调用。
重点是,只有那些被标记为脏的项才会在SaveViewState( )阶段被保存到隐藏字段中。
1.序列化和反序列化
控 件可能拥有子控件。页面是一棵控件树,而Page(或者说ASPX页面)正是这棵树的根。控件树中的每一个控件都拥有自己的ViewState属性,因为 它继承自System.Web.UI.Control。Asp.Net通过递归调用控件树上每一个控件的SaveViewState( )方法来建立一棵数据树(data tree or object tree),这棵数据树与控件树不同在于,它保存的是SaveViewState( )返回的object对象。而SaveViewState( )方法返回的object将被序列化后存储到_ViewState这个隐藏字段中。
2.自动恢复数据
页 面的生命周期中,在加载ViewState之前(即调用控件的LoadViewState( )方法之前)StateBag可能已经有值了,这些值可能来自ASPX中持久化的属性值,也可能是在LoadViewStae( )被调用之前(即OnInit事件之前)被人为地设置了值(即人为地为StateBag增加了StateItem)。如果某个控件在 LoadViewState( )被调用前存入了一个在LoadViewState( )期间会处理到的相同的键,那么之前存入的项可能会被覆盖。原因是LoadViewState( )会加载上一次请求中被标记为脏的项。
英文原文出处:http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx