Asp.Net 4.0 新特性之 使用自定义OutputCache Provider
在Asp.Net 4.0 的web.config文件中添加了关于缓存的配置节,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | < 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中,否则缓存到文件中,如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | 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中定义,例如
1 2 | <%@ 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返回不同的实现名字,如下例子
1 2 3 4 5 6 7 8 9 | 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等
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2008-05-16 在内网服务器中获得真正的客户端ip的方法
2007-05-16 佛经上一百八十一条做人的道理