在我目前参与设计的基于B/S体系的.NET分布式解决方案中,需要对Web界面服务层进行一定的性能优化以满足项目操作需求中关于保障终端浏览器在使用低速网络(如33.6/56kbps的调制解调器)时的响应速度的要求。使用ASP.NET开发的朋友们应该知道,我们在使用ASP.NET提供的众多RAD特性的时候,也是付出了一定的带宽和性能代价的,比如比较典型的例子就是对ViewState的不恰当使用。因此对界面服务层的很多性能优化都是在ViewState上做文章。
举个例子,在我们的方案中有大量的Web Form界面组件,其中大量应用了DataGrid等数据列表显示控件。这些组件大量使用了ViewState来保存列表本身的数据。如果你禁用了它的ViewState以减少页面传输数据量,则为了保持这些组件的状态(尤其是其中动态创建的子控件的状态)必须在页面Postback的时候重新绑定数据(当然,这时候可以有选择的使用服务器端的缓冲技术减少对后台数据库的压力)。
根据我的经验,以DataGrid为例,一般有这么几种使用情况:
1、显示一组数据,并允许用户进行添加、删除、修改等操作。一般而言,用于添加新数据的命令控件是独立于列表控件且静态声明的。然而删除、修改等命令控件基本都是在数据控件绑定数据时动态创建的。
2、若用户选择创建新数据,我们的用例是要求把用户导向用于创建新数据项的单独页面。也就是说,数据显示页面在执行此操作的时候不依赖于数据控件当前的状态。这种情况下,在Postback时是不需要数据控件原有的ViewState,且不需要对其重新进行数据绑定(即将转向其它页面了)。
3、若用户选择删除一条数据,我们的用例是要求刷新数据列表以反映操作结果。既然数据控件中的数据将被更新,则实际上不需要其原有的ViewState(但实际不然,见后文分析),因为在执行所请求的操作后需要对其重新进行数据绑定。
4、若用户选择更新一条数据,我们的用例是要求将用户转到用于修改所选数据项的页面。这种情况下,数据控件原有的ViewState是不需要的,因为马上就要转向其它页面。待修改完成再回到列表显示页面时,数据将被重新获取并绑定到数据控件上。
可以看出,在不需要就地数据编辑(比较适用于带宽较好的应用环境)的情形下,基本上是不需要在每次页面生成后保留数据控件的ViewState的。但这马上带来一个问题,如果Postback是由“数据绑定中动态创建的控件”引发的话,则在Postback回来Page_Load之后这个引发事件的控件必须仍然存在,而为了让这个控件在Postback回来的时候还存在,你只有两个选择:或者保留数据控件的ViewState让其自动恢复原来控件组合状态,或者你重新绑定数据,在这个过程中原来的控件还可以创建出来(*注意:如果再重新数据绑定的时候数据发生变化或被删除,则有可能事件被转发到错误的动态控件上去!因此最好手动为动态创建的控件设定ID使其可以对应到相关连的数据项上)。
以删除一条数据为例,如果用户按了某一行上的一个删除按钮,则该事件被Postback到后台页面处理的时候,ASP.NET页面处理引擎将解析到触发事件的按钮并将该事件转发给它的事件处理程序。在事件处理程序中我们其实只需要知道要删的是哪一行(或简单说,要删的那个数据的ID是什么)就足够了。而为了这一点信息,你或者要把整个数据控件的状态通过ViewState传来传去,或者在Page_Load的时候重新绑定数据——一切就为了一个可以定位操作目标的ID!