在前面两篇文章中,我们了解了VIEWSTATE的相关知识。在这里,我们可以再回头思考这个问题:什么时候可以禁用VIEWSTATE?如果感到这个问题太抽象,那么考虑下面这个问题:
仅就我们在第一节中实现的效果为例,如果禁用掉VIEWSTATE,如何实现启用VIEWSTATE时同样的效果?
对于已经习惯了asp.net机制的同学来说,这无疑将是一个痛苦的过程。更不用说在GridView等控件中,VIEWSTATE说起到的关键作用了(参考烙馅饼喽同学的评论)。VIEWSTATE为我们做了太多的事情,我都有点想向这位默默无闻的英雄致敬了,呵呵!
但是这里有一个无法回避的问题,VIEWSTATE增大了页面。似乎正应了那句古话:“鱼和熊掌,不可兼得!”
所以可能会有同学提出以下的问题:
1. 我的确需要存储GridView的控件状态,因为我不想每次都去数据库读取数据进行绑定运算(据说数据库的操作经常是系统的性能瓶颈);
2. 但是我又不希望出现大量的VIEWSTATE;
3. 而且我已经习惯了ASP.NET的处理方式,不希望对程序进行太多额外的改动。
有办法么?
呵呵,有的。从APS.NET2.O开始,微软为我们提供了!顾名思义,这个类可以将VIEWSTATE存储在Session中,而不是Hidden Input中。这可以用于大数量级的VIEWSTATE处理,它的实现也异常简单,只需要在页面后台(cs文件)中添加代码即可。
然后,我们可以比较使用了SessionPagePersister的页面源代码和未使用SessionPagePersister的页面源代码,可以看到,VIEWSTATE的大小差距。
默认未使用SessionPagePersister。
但是,这背后,究竟发生了什么?
我们首先应该知道,在页面中,我们可以重写这两个方法(sp1234将VIEWSTATE存入服务器磁盘的方法就是这样实现的):
LoadPageStateFromPersistanceMedium():
SavePageStateFromPersistanceMedium():
望文生义,我们就可以知道,以上这两个方法是用于加载(Load)和保存(Save)页面状态(PageState)到一个可持久化(Persistance)的介质(Medium)中的。如果用reflactor查看这两个方法,你会发现,他们其实只是封装了一个PageStatePersister实例的Load或Save方法。
PageStatePersister其实是一个抽象类,它封装了处理VIEWSTATE的主要方法和属性(详细请参考MSDN)。
它有两个子类:
1. HiddenFieldPageStatePersister: 实现了将VIEWSTATE存放到 hidden input中(默认方式)
2. SessionPageStatePersister: 实现了将VIEWSTATE存放到session中
所以,当我们在页面中重写PageStatePersister属性之后,ASP.NET框架将使用SessionPageStatePersister来Load()和Save() VIEWSTAE。(这就是“面向对象”的强大之处!ASP.NET内部似乎还使用了Adapter设计模式,所以使得我们使用起来觉得异常的简单。)
有人认为,这是对糟糕的VIEWSTATE状态机制的一种“补救”,但我更倾向于认为这是一种“扩展”——他仅仅是另一种选择而已,我们必须认识到:使用Session,也只是将负担转移到服务器内存而已。而Session的一个大问题是:它无法实时的清除,通常我们只是设定一个固定的“到期时间”,这无疑是比较缺乏灵活性的(过期时间设得过长,会造成内存资源的浪费;而过期时间设得过短,将会导致信息的丢失)。