[VS2010] ASP.NET 4.0 新功能:自訂輸出快取 (Output Cache) 提供者
輸出快取是 ASP.NET 開發以來重要的功能之一,快取機制是由伺服器的記憶體提供,將網頁或資料的一部份或全部暫存在記憶體中,以提供更快速的回應時間 (response time),並減少伺服器處理與回傳資料的負載,讓應用程式可以服務更多來自用戶端的呼叫,而且輸出快取就單純是暫存快取資料,因此在 ASP.NET 不斷的升級之時,輸出快取沒有做太多的改變,然而這段期間快取的需求卻不斷變化,同時來自大型應用程式的 Load Balancing 架構以及 Web Farm 應用程式的架構下,不同的用戶端會導向到不同的 Server,而快取資料卻只能存在單一台 Server 的記憶體,這會造成快取資料形同虛設,它只能對一小部份的用戶端有作用,沒有連接到存有快取的 Server 的用戶端就無法存取到快取的資料。這促使了微軟必須要將快取機制做修改,以能夠提供除了記憶體以外的快取儲存區,像是檔案或資料庫等,以在不同情況下的快取能夠服務到最多的用戶端,這樣才能夠真正發揮快取的作用,尤其是在大型應用程式中。
ASP.NET 4.0 的輸出快取即具備這樣的能力,ASP.NET 4.0 的 Core Service 將 Output Cache 改寫成使用 Provider Model,讓開發人員可以利用設計自己的 Provider 的方式,讓 ASP.NET 可以輸出快取資料到不同的快取儲存體,而且開發人員也可以將快取與現有具高效率的快取提供者做連接,像是 memcache 這個受歡迎的 Open Source Cache Provider。開發人員可以實作在 System.Web.Caching 命名空間中的 OutputCacheProvider 抽象類別中的各個成員,並且在 Web.config 中加掛這個類別,即可讓 ASP.NET 使用這個類別來提供快取機制。下列程式碼即是一個 OutputCacheProvider 的範例實作:
public class FileCacheProvider : OutputCacheProvider
{
private string _cachePath;
private string CachePath
{
get
{
if (!string.IsNullOrEmpty(_cachePath))
return _cachePath;
_cachePath = ConfigurationManager.AppSettings["OutputCachePath"];
var context = HttpContext.Current;
if (context != null)
{
_cachePath = context.Server.MapPath(_cachePath);
if (!_cachePath.EndsWith("\\"))
_cachePath += "\\";
}
return _cachePath;
}
}
public override object Add(string key, object entry, DateTime utcExpiry)
{
Debug.WriteLine("Cache.Add(" + key + ", " + entry + ", " + utcExpiry +")");
var path = GetPathFromKey(key);
if (File.Exists(path))
return entry;
using (var file = File.OpenWrite(path))
{
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
}
return entry;
}
public override object Get(string key)
{
Debug.WriteLine("Cache.Get(" + key + ")");
var path = GetPathFromKey(key);
if (!File.Exists(path))
return null;
CacheItem item = null;
using (var file = File.OpenRead(path))
{
var formatter = new BinaryFormatter();
item = (CacheItem)formatter.Deserialize(file);
}
if (item == null || item.Expires <= DateTime.Now.ToUniversalTime())
{
Debug.WriteLine("Expired: " + item.Expires + " <= " + DateTime.Now.ToUniversalTime());
Remove(key);
return null;
}
return item.Item;
}
public override void Remove(string key)
{
Debug.WriteLine("Cache.Remove(" + key + ")");
var path = GetPathFromKey(key);
if (File.Exists(path))
File.Delete(path);
}
public override void Set(string key, object entry, DateTime utcExpiry)
{
Debug.WriteLine("Cache.Set(" + key + ", " + entry + ", " + utcExpiry + ")");
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var path = GetPathFromKey(key);
using (var file = File.OpenWrite(path))
{
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
}
}
private string GetPathFromKey(string key)
{
return CachePath + MD5(key) + ".txt";
}
private string MD5(string s)
{
MD5CryptoServiceProvider provider;
provider = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(s);
StringBuilder builder = new StringBuilder();
bytes = provider.ComputeHash(bytes);
foreach (byte b in bytes)
builder.Append(b.ToString("x2").ToLower());
return builder.ToString();
}
}
然後在 Web.config 中將這個 Provider 加掛上 ASP.NET:
<caching>
<outputCache defaultProvider="FileCache">
<providers>
<add name="FileCache" type="MyCacheProvider.FileCacheProvider, MyCacheProvider"/>
</providers>
</outputCache>
</caching>
如此即可在 ASP.NET 中使用自訂的快取提供者給 ASP.NET Cache 使用:
參考資料與圖片來源: