存储位置优化——把视图状态信息保存在服务端而非客户端
本文节选自《庖丁解牛:纵向切入ASP.NET 3.5控件和组件开发技术》一书
视图状态信息默认情况下是存储在客户端的,不占用服务端资源(这里是指持续地占用服务器资源一定时间,视图状态只是在页面呈现时,服务端正反向解析视图状态内容占用一会服务器内存,当页面呈现完成后则会把视图存储到页面上的隐藏控件域中)。当页面结构比较复杂时,会导致视图信息字节数比较大,则会产生带宽瓶颈。为了解决这个问题我们可以选择把视图信息存储到服务器端,或数据库中,或文件等存储介质。这一节我们就以把视图状态存储到服务端Session中为例,说明其实现方法。
新建一个页面SessionPageStatePersister.aspx,页面中的内容仍然使用前面的控件状态控件的测试页面内容,设置好页面内容后,在后台代码中重写基类Page的PageStatePersister属性,如下所示:
/// <summary>
/// 获得本书更多内容,请看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
public partial class Page_SessionPageStatePersister : System.Web.UI.Page
{
protected override PageStatePersister PageStatePersister
{
get
{
return new SessionPageStatePersister(this);
}
}
}
为了更容易理解,下面是Page对该属性的系统默认实现源代码:
protected virtual PageStatePersister PageStatePersister
{
get
{
if (this._persister == null)
{
PageAdapter pageAdapter = this.PageAdapter;
if (pageAdapter != null)
{
this._persister = pageAdapter.GetStatePersister();
}
if (this._persister == null)
{
this._persister = new HiddenFieldPageStatePersister(this);
}
}
return this._persister;
}
}
ASP.NET的默认持久性机制是使用HiddenFieldPageStatePersister类将视图状态存储在客户端,即系统默认实现是在属性PageStatePersister中返回HiddenFieldPageStatePersister类实例,表示存储在客户端的隐藏域中。上面我们重写该属性,返回SessionPageStatePersister类实例,SessionPageStatePersister类表示在Web服务器Session会话中存储ASP.NET页视图状态。
OK,运行一下页面,并查看一下它的隐藏域视图信息,会发现__VIEWSTATE由原来的:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value= "/wEPDwUJNzIxMjkzNTM2D2QWAgIDD2QWBAIBDw8WAh4OVGV4dF9WaWV3U3RhdGUFIuaIkeaYr+eUqFZpZXdTdGF0ZeWuueWZqOWtmOWCqOeahCFkZAIHDw8WAh4EVGV4dAWQBHRoaXMuQ29udHJvbFN0YXRlQ29udHJvbDEuVGV4dF9Ob1ZpZXdTdGF0ZeWxnuaApyDmsqHmnInkv53lrZjmjqfku7bnirbmgIEgPEltZyBzcmM9Jy4uXEltYWdlc1xKUy5qcGcnIC8+ICA8YnI+PGJyPnRoaXMuQ29udHJvbFN0YXRlQ29udHJvbDEuVGV4dF9WaWV3U3RhdGXlsZ7mgKcg5bey57uP5L+d5a2Y5LqG5o6n5Lu254q25oCBIDxJbWcgc3JjPScuLlxJbWFnZXNcWEwuanBnJyAvPiAgPGJyPjxicj50aGlzLkNvbnRyb2xTdGF0ZUNvbnRyb2wxLkZhY2VTdHlsZeWxnuaApy5PSyDlt7Lnu4/kv53lrZjkuobmjqfku7bnirbmgIEgPEltZyBzcmM9Jy4uXEltYWdlc1xYTC5qcGcnIC8+ICA8YnI+PGJyPnRoaXMuQ29udHJvbFN0YXRlQ29udHJvbDEuRmFjZVN0eWxlLkJhY2tDb2xvciDlt7Lnu4/kv53lrZjkuobmjqfku7bnirbmgIEsIOeep++8jOaIkeeahOminOiJsuWwseaYr+S/neWtmOeahOminOiJsiA8SW1nIHNyYz0nLi5cSW1hZ2VzXFhMLmpwZycgLz4gIDxJbWcgc3JjPScuLlxJbWFnZXNcQkcuanBnJyAvPiA8YnI+PGJyPmRkGAEFFENvbnRyb2xTdGF0ZUNvbnRyb2wxDw8PFgIfAAUi5oiR5piv55SoVmlld1N0YXRl5a655Zmo5a2Y5YKo55qEIWQUKwACFgQeCUJhY2tDb2xvcgoAHgRfIVNCAghnZHweEc0h/1gIsxczc2fHdmLTQy1x" />
变为现在的:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value= "/wEPaA8FDzhjYTlhMjI1ZDY2NTQ3MxgBBRRDb250cm9sU3RhdGVDb250cm9sMQ8PDxYCHg5UZXh0X1ZpZXdTdGF0ZQUi5oiR5piv55SoVmlld1N0YXRl5a655Zmo5a2Y5YKo55qEIWQUKwACFgQeCUJhY2tDb2xvcgoAHgRfIVNCAghnZNiSxDj0eWw88GLxQrKC0IucFKmW" />
另外,这里的HiddenFieldPageStatePersister和SessionPageStatePersister都是继承基类 System.Web.UI.PageStatePersister,该基类允许自定义持久化机制,如果既不想存储到客户端隐藏域中,也不想存储到Session中,可以定义该类的派生类,实现自定义持久化机制。在6.8.2小节有一个派生System.Web.UI.PageStatePersister 类的例子。
除了使用重写基类Page的PageStatePersister属性实现指定持久化类对象外,还可以通过实现System.Web.UI.Adapters.PageAdapter类的页配器实现同样功能。PageAdapter类是一个抽象类,可以修改网页以适应特定的浏览器,并提供所有页面适配器可直接或间接继承的基类。下面是一个自定义页适配器的例子:
/// <summary>
/// 获得本书更多内容,请看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
public class SessionPageAdapter : System.Web.UI.Adapters.PageAdapter
{
public override PageStatePersister GetStatePersister()
{
return new SessionPageStatePersister(this.Page);
}
}
然后在站点下面添加App_Browsers目录,并添加一个文件名称为SessionPageAdapter.browser的文件,内容如下:
<browsers>
//… …
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page" adapterType="KingControls. SessionPageAdapter" />
</controlAdapters>
</browser>
</browsers>
运行一下页面,也会发现得到与之前相同的效果。这两种方法都能够在服务器Session中存储视图信息。不同的一点是后面这种方式影响到了整个站点下面的所有页面。
Session一般用于存储特定于单独会话的短期信息,比存储到客户端隐藏域中方式要安全得多。但这种方式要占用服务器内存,因此在客户端比较多的情况下不要在Session中存储大量的信息。
···
···