Skip Navigation Links
技术文档
·网站建设
·软件使用
·图形设计
·程序开发
·网络应用
·电脑技巧
 
公司介绍
·公司简介
·索仕SRCOS网络应用平台
·索仕网站管理系统
·影视广告制作
·联系我们
 
 

Asp.Net 4.0 新特性之 使用自定义OutputCache Provider

5/20/2010 12:38:00 PM

 

在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     /// <summary>
013     /// OutputCache精灵,如果缓存时间小于设置时间时则缓存到内存,否则缓存到文件
014     /// </summary>
015     public class SmartOutputCacheProvider : OutputCacheProvider
016     {
017         private const string KEY_PREFIX = "__outputCache_";
018  
019         /// <summary>
020         /// 初始化SmartOutputCacheProvider,读取配置文件中配置的MemoryCacheLimit和FileCacheRoot的值
021         /// </summary>
022         /// <param name="name">provider名字</param>
023         /// <param name="config">配置</param>
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         /// <summary>
046         /// 添加缓存
047         /// </summary>
048         /// <param name="key">缓存的键,key的值是有asp.net内部生成的</param>
049         /// <param name="entry">缓存的对象</param>
050         /// <param name="utcExpiry">过期时间</param>
051         /// <returns>返回缓存值</returns>
052         public override object Add(string key, object entry, DateTime utcExpiry)
053         {
054             Set(key, entry, utcExpiry);
055             return entry;
056         }
057  
058         /// <summary>
059         /// 处理缓存键值,防止在文件缓存时出现文件路径不允许的字符
060         /// </summary>
061         /// <param name="key">缓存键</param>
062         /// <returns>处理后的键</returns>
063         private string ProcessKey(string key)
064         {
065             return KEY_PREFIX + System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(key, "MD5");
066         }
067  
068         /// <summary>
069         /// 返回缓存文件的物理路径
070         /// </summary>
071         /// <param name="processedKey">处理后的键</param>
072         /// <returns>物理路径</returns>
073         private string GetFilePath(string processedKey)
074         {
075             return Path.Combine(FileCacheRoot, processedKey + ".data");
076         }
077  
078         /// <summary>
079         /// 获得缓存值,如果在HttpRuntime.Cache中有则直接读取内存中的值,否则从文件读取
080         /// </summary>
081         /// <param name="key">缓存键</param>
082         /// <returns>缓存值</returns>
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         /// <summary>
110         /// 根据键移除缓存
111         /// </summary>
112         /// <param name="key">缓存键</param>
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         /// <summary>
123         /// 设置缓存
124         /// </summary>
125         /// <param name="key">缓存键</param>
126         /// <param name="entry">缓存内容</param>
127         /// <param name="utcExpiry">过期时间</param>
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         /// <summary>
156         /// 如果缓存设定的时间超过此值则缓存到文件中,否则在HttpRuntime.Cache中做缓存
157         /// </summary>
158         [XmlAttribute("memoryCacheLimit")]
159         public TimeSpan MemoryCacheLimit { getset; }
160  
161  
162         /// <summary>
163         /// 文件缓存的根目录,可以指定任何可访问目录
164         /// </summary>
165         [XmlAttribute("fileCacheRoot")]
166         public string FileCacheRoot { getset; }
167     }
168  
169     /// <summary>
170     /// 对缓存数据和缓存的过期时间的封装
171     /// </summary>
172     [Serializable]
173     internal class CacheDataWithExpiryTimeUtc
174     {
175         public object Data { getset; }
176  
177         public DateTime ExpiryTimeUtc { getset; }
178     }
179 }

2.如何使用自定义的OutputCacheProvider

  1)在配置文件中做配置,将自定义的实现作为默认输出缓存支持,请看文章开始的配置
  2)在UserControl中指定使用Provider的名字,改名字在web.config中定义,例如

1 <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="IamUserControl.ascx.cs" Inherits="OutputCacheTest.IamUserControl" %>
2 <%@ OutputCache Duration="3000" ProviderName="AspNetInternalProvider" VaryByParam="None" %>

  需要注意的是,只能在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或者其他键值对数据存储中,从而使程序的性能达到最优的情况。

请注意:本文举例中的代码仅为示例代码,实际应用中需要考虑很多因素。

示例代码下载

本文附件:
OutputCacheTest.rar
作者:玉开 来源:博客园
 
 
 
昆明索仕科技开发有限公司 版权所有 Copyright© 2002-2010 Kunming Source Technology Exploitive Co.,LTD. All Rights Reserved.
电话:0871-5627877 业务QQ:163871 联系我们
本站基于:索仕网站信息管理系统建设 版本 2.0.4325