在Web开发中,页面状态管理是一个重要的议题。ASP.NET提供了ViewState机制来帮助开发者在页面间保持状态。ViewState是一种在客户端和服务器端之间传输数据的技术,它允许开发者在页面回发时保持控件的状态。然而,ViewState的默认实现可能会对页面性能产生负面影响,因为它会增加页面的大小。本文将探讨ViewState的工作原理、如何优化它以及一些高级技巧。
在ASP.NET中,ViewState用于在页面回发时保持控件的状态。ViewState的数据默认被序列化并作为隐藏的表单输入发送到客户端浏览器。当查看使用ViewState的页面源代码时,可能会看到类似于以下的隐藏输入字段:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTM1ODM3Nj......." />
这个隐藏字段包含了页面上所有控件的ViewState值。这是ViewState的一个重要特性,需要开发者注意。
由于ViewState默认会发送到客户端浏览器,然后在页面上以隐藏输入控件的形式返回到服务器,因此在ViewState中存储大量数据会增加页面大小,从而影响页面性能。为了禁用控件的ViewState,可以将EnableViewState属性设置为false(在ASP.NET 2.0中,ViewState默认是启用的)。当ViewState被禁用时,该控件的所有子控件的ViewState也会被自动禁用。
以下是一个禁用ViewState的示例:
<asp:Label ID="lblRequestCount" runat="server" EnableViewState="false"></asp:Label>
这并不意味着应该避免使用ViewState。然而,应该始终清楚在ViewState中存储了什么,以及它如何影响整体页面大小。
一个在ViewState中存储小值的简单方法是使用属性而不是成员变量。这个属性可以使用ViewState来存储其值,而不是在回发时会丢失值的成员变量。例如,像这样在ViewState中存储一个整数:
Public Property SomeInteger() As Integer
Get
Dim o As Object = ViewState("SomeInteger")
If Not o Is Nothing Then
Return DirectCast(o, Integer)
End If
Return 0 ' 默认值
End Get
Set(ByVal value As Integer)
ViewState("SomeInteger") = value
End Set
End Property
在某些情况下,比如页面上有大量的服务器控件或者在ViewState中存储了大量自定义数据,页面ViewState数据的大小可能会变得很大。页面的ViewState数据被编码并存储在HTML隐藏元素中,并作为页面的一部分发送到客户端。拥有一个较大的ViewState可能会影响Web应用程序的性能,因为它增加了客户端需要下载的总页面大小(包括编码的ViewState)。一个明显的改进页面大小的方法是控制ViewState中的内容。但在某些情况下,可能没有太多选择,只能接受它的现状。在这种情况下,可以压缩ViewState数据或者将ViewState存储在页面之外的地方,比如会话状态。是的,ASP.NET确实提供了自定义ViewState存储位置的方法。
为了自定义页面ViewState的持久化部分,需要重写Page类的SavePageStateToPersistenceMedium和LoadPageStateFromPersistenceMedium方法。SavePageStateToPersistenceMedium在页面生命周期中ViewState准备持久化时被调用;ASP.NET调用这个方法时会传递ViewState对象,可以根据需要处理这个对象,只要能够在ASP.NET通过后者方法LoadPageStateFromPersistenceMedium请求它时将其返回即可。顾名思义,这个方法在状态持久化自定义方面与前者相反。以下代码示例展示了如何将ViewState存储在会话状态变量中,以会话ID为键:
protected override object LoadPageStateFromPersistenceMedium()
{
return (new LosFormatter().Deserialize((string)Session[Session.SessionID]));
}
protected override void SavePageStateToPersistenceMedium(object state)
{
LosFormatter los = new LosFormatter();
StringWriter sw = new StringWriter();
los.Serialize(sw, state);
string vs = sw.ToString();
Session[Session.SessionID] = vs;
}
一旦上述代码就位,页面中用于ViewState数据的HTML隐藏元素应该是空的:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" />