总有人问“如何提高页面生成速度”的问题。说实在,这类问题“不要其烦”,我反而很奇怪怎么会有那么多人不知道答案呢?想来想去,大概是因为缓存效果不容
易看到的原因,似乎到底有没有缓存在自己开发机器上总是需要一些想象力才能看清楚。这里我就给一个最简单的例子,其实网上也有很多“范例”。
假设我们在一个页面中有一个部分是显示网站地图的树状菜单,也就是一下两句话:
<asp:TreeView ID="TreeView1" runat="server" ShowLines="True" DataSourceID="SiteMapDataSourceForTreeView" />
<asp:SiteMapDataSource ID="SiteMapDataSourceForTreeView" runat="server" />
并且假设还要在网页产生时(例如PreRender事件中)删除一些树节点。例如我就觉得使用roleprovider是对我已经有的系统复杂化,我只使
用login控件,我的每一个用户都有多个role,因此roleprovider并不适合我。我在上面这个TReeView1显示时就必须看一下
Nodes和ChildNodes,看看节点的 NavigateUrl 是不是当前登录的用户的role所支持的。
此时,我们不需要每当页面回发就重新创建TreeView1,更不希望总是重复这个删除节点过程。那么就需要将这两条代码“片段缓存”起来。
我们首先需要把这两条代码移到一个用户控件中,主页面使用这个用户控件。这仅需要半分钟。不错,vs可以在主页面设计时即时显示用户控件的图像。然后,我们要加上一个测试控件,就是在上面两个代码后边加上一条语句:
<asp:Label ID="TestLabel" runat="server" EnableViewState="False"> </asp:Label>
注意,这个Label是禁止ViewState的!在刷新是它总是丢弃原来的Text(实际上丢弃了运行时设置的一切状态)。
接下来,我们要验证我们的TreeView何时刷新。选择TreeView1控件,在属性窗口中点击事件 OnDataBound,然后添加一行代码:
TestLabel.Text = DateTime.Now.ToLongTimeString();
然后就可以按“F5”运行。可以看到,当主页面回发时(例如按一个Button时),TestLabel中打印出不同的值,说明OnDataBound在此时执行了。
我们不希望它这么频繁地执行,而仅仅希望在用户注册码(保存在名为passport的cookie中)改变时才执行,也就是片段缓存整个用户控件。我们可以为用户控件第二行添加上:
<%@ OutputCache Duration="600" VaryByParam="none" VaryByCustom="cao" Shared="true" %>
这会缓存10分钟!
接下来,在global.ascx中添加代码来控制缓存刷新:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "cao" && context.Request.Cookies["passport"] != null)
return context.Request.Cookies["passport"].Value;
return base.GetVaryByCustomString(context, custom);
}
再次按“F5”运行,就可以看到TestLabel证明绑定TreeView没有被绑定,直到我们的网页上更新了这个cookie值时才重新绑定!
缓存应该用在asp.net网站的方方面面。例如使用ObjectDataSource、SqlDataSource控件等来缓存大量查询数据,以及使用
OutputCache来缓存页面内容。总之,要尽量使用asp.net现成的工具来实现网站,尽量少地手工写代码,才能为快速优化网站打下基础。每一个
asp.net工具已经完成的事情都自己写代码去完成,虽然能够去学习asp.net的某些机制,也让你忽略了asp.net的某些高级的机制。如果你觉
得asp.net不够高级,继承它的组件然后扩展它,不要轻易地“从底层开发”与之功能类似的组件。