Asp.Net 4.0 新特性之 使用自定義OutputCache Provider(轉)

iDotNetSpace發表於2010-05-17

在Asp.Net 4.0 的web.config檔案中新增了關於快取的配置節,如下所示:

01 <system.web>
02   <compilation debug="true" targetFramework="4.0" />
03   <caching>
04     <outputCache defaultProvider="SmartOutputCache">
05       <providers>
06         <add name="SmartOutputCache" type="OutputCacheTest.Caching.SmartOutputCacheProvider" 
07              memoryCacheLimit="00:30:00"
08              />
09       providers>
10     outputCache>
11   caching>
12 system.web>

我們可以在Web.config中配置自定義的OutputCacheProvider,並將自定義Provider指定為預設的Provider。

1.自定義OutputCacheProvider需要實現System.Web.Cacheing. OutputCacheProvider抽象類,網上有很多例子都用檔案快取做例子。這個例子太俗了,我寫了一個新的例子,在設定的快取時間小於指定閥值時,快取到HttpRuntime.Cache中,否則快取到檔案中,如下程式碼:

001 using System;
002 using System.Collections.Generic;
003 using System.Linq;
004 using System.Web;
005 using System.Web.Caching;
006 using System.Xml.Serialization;
007 using System.IO;
008 using System.Runtime.Serialization.Formatters.Binary;
009   
010 namespace OutputCacheTest.Caching
011 {
012     ///
013     /// OutputCache精靈,如果快取時間小於設定時間時則快取到記憶體,否則快取到檔案
014     ///
015     public class SmartOutputCacheProvider : OutputCacheProvider
016     {
017         private const string KEY_PREFIX = "__outputCache_";
018   
019         ///
020         /// 初始化SmartOutputCacheProvider,讀取配置檔案中配置的MemoryCacheLimit和FileCacheRoot的值
021         ///
022         /// provider名字
023         /// 配置
024         public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
025         {
026             string memoryLimit = config["memoryCacheLimit"];
027             if (memoryLimit == null)
028             {
029                 MemoryCacheLimit = new TimeSpan(0, 30, 0);
030             }
031             else
032             {
033                 MemoryCacheLimit = TimeSpan.Parse(memoryLimit);
034             }
035   
036             string fileCacheRoot = config["fileCachRoot"];
037             if (string.IsNullOrEmpty(fileCacheRoot))
038             {
039                 fileCacheRoot = AppDomain.CurrentDomain.BaseDirectory + "cache\\";
040             }
041             this.FileCacheRoot = fileCacheRoot;
042             base.Initialize(name, config);
043         }
044   
045         ///
046         /// 新增快取
047         ///
048         /// 快取的鍵,key的值是有asp.net內部生成的
049         /// 快取的物件
050         /// 過期時間
051         /// 返回快取值
052         public override object Add(string key, object entry, DateTime utcExpiry)
053         {
054             Set(key, entry, utcExpiry);
055             return entry;
056         }
057   
058         ///
059         /// 處理快取鍵值,防止在檔案快取時出現檔案路徑不允許的字元
060         ///
061         /// 快取鍵
062         /// 處理後的鍵
063         private string ProcessKey(string key)
064         {
065             return KEY_PREFIX + System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(key, "MD5");
066         }
067   
068         ///
069         /// 返回快取檔案的物理路徑
070         ///
071         /// 處理後的鍵
072         /// 物理路徑
073         private string GetFilePath(string processedKey)
074         {
075             return Path.Combine(FileCacheRoot, processedKey + ".data");
076         }
077   
078         ///
079         /// 獲得快取值,如果在HttpRuntime.Cache中有則直接讀取記憶體中的值,否則從檔案讀取
080         ///
081         /// 快取鍵
082         /// 快取值
083         public override object Get(string key)
084         {
085             string processedKey = ProcessKey(key);
086   
087             CacheDataWithExpiryTimeUtc result = HttpRuntime.Cache[processedKey] as CacheDataWithExpiryTimeUtc;
088             if (result == null)
089             {
090                 string path = GetFilePath(processedKey);
091                 if (!File.Exists(path))
092                     return null;
093   
094                 using (FileStream file = File.OpenRead(path))
095                 {
096                     var formatter = new BinaryFormatter();
097                     result = (CacheDataWithExpiryTimeUtc)formatter.Deserialize(file);
098                 }
099             }
100   
101             if (result == null || result.ExpiryTimeUtc <= DateTime.UtcNow)
102             {
103                 Remove(key);
104                 return null;
105             }
106             return result.Data;
107         }
108   
109         ///
110         /// 根據鍵移除快取
111         ///
112         /// 快取鍵
113         public override void Remove(string key)
114         {
115             string processedKey = ProcessKey(key);
116             HttpRuntime.Cache.Remove(processedKey);
117             string path = GetFilePath(processedKey);
118             if (!File.Exists(path))
119                 File.Delete(path);
120         }
121   
122         ///
123         /// 設定快取
124         ///
125         /// 快取鍵
126         /// 快取內容
127         /// 過期時間
128         public override void Set(string key, object entry, DateTime utcExpiry)
129         {
130             TimeSpan ts = utcExpiry - DateTime.UtcNow;
131             string processedKey = ProcessKey(key);
132   
133             CacheDataWithExpiryTimeUtc cacheItem = new CacheDataWithExpiryTimeUtc
134             {
135                 Data = entry,
136                 ExpiryTimeUtc = utcExpiry
137             };
138   
139             if (ts <= MemoryCacheLimit)
140             {
141                 HttpRuntime.Cache.Insert(processedKey, cacheItem, null, utcExpiry.ToLocalTime(), TimeSpan.Zero);
142             }
143             else
144             {
145                 string cacheFilePath = GetFilePath(processedKey);
146                   
147                 using (var fs = new FileStream(cacheFilePath,FileMode.OpenOrCreate,FileAccess.ReadWrite))
148                 {
149                     var formatter = new BinaryFormatter();
150                     formatter.Serialize(fs, cacheItem);
151                 }
152             }
153         }
154   
155         ///
156         /// 如果快取設定的時間超過此值則快取到檔案中,否則在HttpRuntime.Cache中做快取
157         ///
158         [XmlAttribute("memoryCacheLimit")]
159         public TimeSpan MemoryCacheLimit { get; set; }
160   
161   
162         ///
163         /// 檔案快取的根目錄,可以指定任何可訪問目錄
164         ///
165         [XmlAttribute("fileCacheRoot")]
166         public string FileCacheRoot { get; set; }
167     }
168   
169     ///
170     /// 對快取資料和快取的過期時間的封裝
171     ///
172     [Serializable]
173     internal class CacheDataWithExpiryTimeUtc
174     {
175         public object Data { get; set; }
176   
177         public DateTime ExpiryTimeUtc { get; set; }
178     }
179 }

2.如何使用自定義的OutputCacheProvider

  1)在配置檔案中做配置,將自定義的實現作為預設輸出快取支援,請看文章開始的配置
  2)在UserControl中指定使用Provider的名字,改名字在web.config中定義,例如

  需要注意的是,只能在UserControl中指定Provider的名字,在Page的生明中是不允許的,在Page中預設情況會使用web.config中配置的defaultProvider,但是我們可以通過3)中介紹的方法給不同的頁面使用不同的OutputCacheProvider實現。

  3)在Global.asax檔案中重寫GetOutputCacheProviderName(HttpContext context)方法,根據context返回不同的實現名字,如下例子

1 public override string GetOutputCacheProviderName(HttpContext context)
2 {
3     if (context.Request.Path.StartsWith("/default.aspx",StringComparison.CurrentCultureIgnoreCase))
4     {
5         return "AspNetInternalProvider";
6     }
7               
8     return base.GetOutputCacheProviderName(context);
9 }

總結:
可擴充套件的OutputCache為我們提供了無限的可能,我們可以根據需要擴充套件OutputCache,例如把OutputCache儲存到Memcached server或者其他鍵值對資料儲存中,從而使程式的效能達到最優的情況。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-662874/,如需轉載,請註明出處,否則將追究法律責任。

相關文章