在Asp.Net 4.0 的web.config檔案中添加了關於緩衝的配置節,如下所示:
<system.web> <compilation debug="true" targetFramework="4.0" /> <caching> <outputCache defaultProvider="SmartOutputCache"> <providers> <add name="SmartOutputCache" type="OutputCacheTest.Caching.SmartOutputCacheProvider" memoryCacheLimit="00:30:00" /> </providers> </outputCache> </caching> </system.web>
我們可以在Web.config中配置自訂的OutputCacheProvider,並將自訂Provider指定為預設的Provider。
1.自訂OutputCacheProvider需要實現System.Web.Cacheing. OutputCacheProvider抽象類別,網上有很多例子都用檔案快取做例子。這個例子太俗了,我寫了一個新的例子,在設定的緩衝時間小於指定閥值時,緩衝到HttpRuntime.Cache中,否則緩衝到檔案中,如下代碼:
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Caching;using System.Xml.Serialization;using System.IO;using System.Runtime.Serialization.Formatters.Binary;namespace OutputCacheTest.Caching{ /// <summary> /// OutputCache精靈,如果緩衝時間小於設定時間時則緩衝到記憶體,否則緩衝到檔案 /// </summary> public class SmartOutputCacheProvider : OutputCacheProvider { private const string KEY_PREFIX = "__outputCache_"; /// <summary> /// 初始化SmartOutputCacheProvider,讀取設定檔中配置的MemoryCacheLimit和FileCacheRoot的值 /// </summary> /// <param name="name">provider名字</param> /// <param name="config">配置</param> public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) { string memoryLimit = config["memoryCacheLimit"]; if (memoryLimit == null) { MemoryCacheLimit = new TimeSpan(0, 30, 0); } else { MemoryCacheLimit = TimeSpan.Parse(memoryLimit); } string fileCacheRoot = config["fileCachRoot"]; if (string.IsNullOrEmpty(fileCacheRoot)) { fileCacheRoot = AppDomain.CurrentDomain.BaseDirectory + "cache\\"; } this.FileCacheRoot = fileCacheRoot; base.Initialize(name, config); } /// <summary> /// 添加緩衝 /// </summary> /// <param name="key">緩衝的鍵,key的值是有asp.net內部產生的</param> /// <param name="entry">緩衝的對象</param> /// <param name="utcExpiry">到期時間</param> /// <returns>返回緩衝值</returns> public override object Add(string key, object entry, DateTime utcExpiry) { Set(key, entry, utcExpiry); return entry; } /// <summary> /// 處理緩衝索引值,防止在檔案快取時出現檔案路徑不允許的字元 /// </summary> /// <param name="key">緩衝鍵</param> /// <returns>處理後的鍵</returns> private string ProcessKey(string key) { return KEY_PREFIX + System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(key, "MD5"); } /// <summary> /// 返回快取檔案的實體路徑 /// </summary> /// <param name="processedKey">處理後的鍵</param> /// <returns>實體路徑</returns> private string GetFilePath(string processedKey) { return Path.Combine(FileCacheRoot, processedKey + ".data"); } /// <summary> /// 獲得緩衝值,如果在HttpRuntime.Cache中有則直接讀取記憶體中的值,否則從檔案讀取 /// </summary> /// <param name="key">緩衝鍵</param> /// <returns>緩衝值</returns> public override object Get(string key) { string processedKey = ProcessKey(key); CacheDataWithExpiryTimeUtc result = HttpRuntime.Cache[processedKey] as CacheDataWithExpiryTimeUtc; if (result == null) { string path = GetFilePath(processedKey); if (!File.Exists(path)) return null; using (FileStream file = File.OpenRead(path)) { var formatter = new BinaryFormatter(); result = (CacheDataWithExpiryTimeUtc)formatter.Deserialize(file); } } if (result == null || result.ExpiryTimeUtc <= DateTime.UtcNow) { Remove(key); return null; } return result.Data; } /// <summary> /// 根據鍵移除緩衝 /// </summary> /// <param name="key">緩衝鍵</param> public override void Remove(string key) { string processedKey = ProcessKey(key); HttpRuntime.Cache.Remove(processedKey); string path = GetFilePath(processedKey); if (!File.Exists(path)) File.Delete(path); } /// <summary> /// 設定緩衝 /// </summary> /// <param name="key">緩衝鍵</param> /// <param name="entry">緩衝內容</param> /// <param name="utcExpiry">到期時間</param> public override void Set(string key, object entry, DateTime utcExpiry) { TimeSpan ts = utcExpiry - DateTime.UtcNow; string processedKey = ProcessKey(key); CacheDataWithExpiryTimeUtc cacheItem = new CacheDataWithExpiryTimeUtc { Data = entry, ExpiryTimeUtc = utcExpiry }; if (ts <= MemoryCacheLimit) { HttpRuntime.Cache.Insert(processedKey, cacheItem, null, utcExpiry.ToLocalTime(), TimeSpan.Zero); } else { string cacheFilePath = GetFilePath(processedKey); using (var fs = new FileStream(cacheFilePath,FileMode.OpenOrCreate,FileAccess.ReadWrite)) { var formatter = new BinaryFormatter(); formatter.Serialize(fs, cacheItem); } } } /// <summary> /// 如果緩衝設定的時間超過此值則緩衝到檔案中,否則在HttpRuntime.Cache中做緩衝 /// </summary> [XmlAttribute("memoryCacheLimit")] public TimeSpan MemoryCacheLimit { get; set; } /// <summary> /// 檔案快取的根目錄,可以指定任何可訪問目錄 /// </summary> [XmlAttribute("fileCacheRoot")] public string FileCacheRoot { get; set; } } /// <summary> /// 對快取資料和緩衝的到期時間的封裝 /// </summary> [Serializable] internal class CacheDataWithExpiryTimeUtc { public object Data { get; set; } public DateTime ExpiryTimeUtc { get; set; } }}
2.如何使用自訂的OutputCacheProvider
1)在設定檔中做配置,將自訂的實現作為預設輸出緩衝支援,請看文章開始的配置
2)在UserControl中指定使用Provider的名字,改名字在web.config中定義,例如
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="IamUserControl.ascx.cs" Inherits="OutputCacheTest.IamUserControl" %><%@ OutputCache Duration="3000" ProviderName="AspNetInternalProvider" VaryByParam="None" %>
需要注意的是,只能在UserControl中指定Provider的名字,在Page的生明中是不允許的,在Page中預設情況會使用web.config中配置的defaultProvider,但是我們可以通過3)中介紹的方法給不同的頁面使用不同的OutputCacheProvider實現。
3)在Global.asax檔案中重寫GetOutputCacheProviderName(HttpContext context)方法,根據context返回不同的實現名字,如下例子
public override string GetOutputCacheProviderName(HttpContext context){ if (context.Request.Path.StartsWith("/default.aspx",StringComparison.CurrentCultureIgnoreCase)) { return "AspNetInternalProvider"; } return base.GetOutputCacheProviderName(context);}
總結:
可擴充的OutputCache為我們提供了無限的可能,我們可以根據需要擴充OutputCache,例如把OutputCache儲存到Memcached server或者其他索引值對資料存放區中,從而使程式的效能達到最優的情況。
請注意:本文舉例中的代碼僅為範例程式碼,實際應用中需要考慮很多因素。
範例程式碼下載
Asp.net 新特性相關閱讀:
1. 從頁面標記<%%>說起
2. Asp.Net 4.0 中可以用自訂的Provider做OutputCache 了
3. SEO增強支援MetaKeywords,和MetaDescription,RedirectPermanant
4. SEO增強之URL Routing
5. 輸出更純淨的Html代碼,ViewStateMode和ClientIDMode,CheckBoxList等