说到网站性能优化,没有什么比“缓存”更重要了。即便是某些朋友口中念念不忘的“静态页”,说
到底也只是缓存了整张页面内容而已。但是,显然这样大粒度的缓存策略,在如今“牵一发而动全身”的
Web 2.0站点中几乎是无法使用的。试想,在Twitter中的某个名人被数十万人订阅,那么他发一条消息,
难道此时网站要去修改数十万用户的静态页面?因此,我们需要粒度更小的缓存。而比“整页缓存”粒度
小一号的缓存,便是所谓“视图片断缓存”了。
视图片断缓存非常重要,因为它缓存的也是页面内容,这表示它比更低级别的缓存更有效率,也比静
态页等整页内容缓存的适用面要大得多。在ASP.NET WebForm模型中提供了控件级别的缓存,我们可以为
控件标记输出缓存策略,这样控件便不会每次都完整执行一遍。当然这个策略还不够灵活,因为它缓存的
最小单元是“控件”,而不是页面中任意的部分。因此我在一年多前提出了一个CachePanel,由它包装的
页面内容都可以被缓存,无论其内部是控件还是普通输出的内容。在实际生产过程中,CachePanel起到了
非常重要的作用,许多场景下只要在页面中包裹一个<ext:CachePanel runat="server" />,性能
立即就有了质的飞跃。
只可惜,在如今ASP.NET MVC的时代无法直接使用CachePanel这样的服务器端控件。因为CachePanel需
要服务器端代码的配合,而ASP.NET MVC中的页面只是“视图模板”,除了呈现之外就不应该有其他职责
。因此,我们必须提出一种脱离于后端代码的“标记”方式,将视图中的内容片断进行随意地缓存。在
Rails或Django中都有类似的特性,但ASP.NET MVC甚至在2.0的Road Map中还没有包含这一功能,于是我
们只能自己动手丰衣足食。不过有了ASP.NET WebForm作为强大的视图引擎,加这样的功能简直是举手之
劳:
public static class CacheExtensions
{
public static string Cache
(
this HtmlHelper htmlHelper,
string cacheKey,
CacheDependency cacheDependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
Func<object> func)
{
var
cache = htmlHelper.ViewContext.HttpContext.Cache;
var content = cache.Get
(cacheKey) as string;
if (content == null)
{
content = func().ToString();
cache.Insert(cacheKey, content,
cacheDependencies, absoluteExpiration, slidingExpiration);
}
return content;
}
}