第一节:从程序集的角度分析System.Web.Caching.Cache ,并完成基本封装。
2017-07-25 14:45
351 查看
[b]一. 揭开迷雾[/b]
1. 程序集准备
a. 需要给项目添加 System.Web 程序集。
b. 需要给使用的地方添加两个引用。
2. 程序集探究
在对应的类中输入关键字 Cache,选中点击F12,查看Cache程序集,如下图所示:
我们一起来分析从上往下来分析一下该程序集。
(1). 两个字段,根据类型能看出来,一个是具体的时间点,另一个时间段,我们猜想,他们可能分别对应缓存中的绝对过期时间和相对过期时间。(其实事实也是如此)
(2). 构造函数
注意:通常我们实例化该类型的缓存,一般不直接通过构造函数实例化,我们通常使用 HttpRuntime.Cache 。我们一起来看看HttpRuntime的程序集,其中有个Cache属性,即可以通过它来获取Cache对象的实例。
(3). 顾名思义通俗易懂的属性和方法。
A : Count 属性,获取缓存个数。
B : Get(string key) 方法,根据缓存的键名来获取缓存的值。
C : Remove(string key) 方法,根据缓存的键名来删除缓存的值。
(4). 深究 public IDictionaryEnumerator GetEnumerator();
查看IDictionaryEnumerator的程序集,发现他是一个字典类型的集合,有键有值。
那么问题来了,怎么遍历该字典类型的集合呢?怎么获取对应的键和值呢?F12查看 IEnumerator程序集,发现里面有一个MoveNext()方法,可以推进到集合的下一个元素。
(5). Add和Insert方法,二者都为增加缓存的方法,而且二者最多参数的那个重载参数类型完全相同。不同的是Insert有多种重载方式,而Add只有一种重载。 二者核心差异:当缓存已经存在,用Add添加会报错,但用Insert添加,会直接覆盖更新。
下面以Add为例,一起来分析这七个参数。
A:key: 代表缓存的键名。
B:value:代表缓存的值,可以是任意类型。
C:dependencies:表示缓存的依赖项,可以依赖文件、文件夹、多个文件、以及依赖数据库,如果不需要依赖时,传入参数null。
D:absoluteExpiration:代表绝对过期时间,是个DateTime类型的时间点。如果要启用绝对过期时间,那么slidingExpriation必须为:Cache.NoSlidingExpiration。
该参数表现形式可以是:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00") 。
E:slidingExpiration:代表相对过期时间,是个TimeSpan类型的时间段。 如果要启用相对过期时间,那么absoluteExpiration必须为:Cache.NoAbsoluteExpiration。
该参数的表现形式可以是:: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒 。
F:priority:代表缓存销毁时的移除顺序,优先级低的先销毁。没有特殊要求通常使用: CacheItemPriority.Normal 即可。
G:onRemoveCallBack:是一个无返回值具有三个参数的委托。public delegate void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason);
当缓存过期时,调用该委托。委托的三个参数分别代表的含义为:缓存的键、缓存的值、缓存销毁的原因。
二[b]. 缓存封装[/b]
1. 封装思路
首先我们要清楚,封装的目的是什么? 说白了,方便自己、方便别人的灵活调用;同时便于以后的代码维护,能应对需求的变更。
通常调用的方式有两种:1. 将方法写成static静态方法,直接通过 类名.方法名 来进行调用。(该种方式偏离了面向对象的体系)
2. 将该类实例化,然后用实例化的对象调用该类中的封装方法。
3. 这里暂时不考虑 IOC的方式创建对象。
我们试想,会有什么需求变化呢? 有一天,PM要求,所有使用System.Web.Caching.Cache缓存的地方,都要改成 MemoryCache,如果我们事先没有应对措施,我的天!数不胜数的方法中均是传入的 Cache实例,不支持MemoryCache的实例,排着改?保证你崩溃!!!!!
上述场景,在实际开发中非常常见,解决该问题,我们通常使用DIP原则进行封装(依赖倒置原则,核心面向接口编程)。
所以我们定义一个缓存接口ICache,约束了缓存的定义的规范,然后我们再建立一个 RuntimeCacheHelp 类,对ICache进行了实现,同时也定义自己特有的方法。
2. 话不多说,直接上代码。
接口:
缓存帮助类:
3. 如何调用?调用过程中会存在哪些问题?我们再后续章节中进行介绍。
1. 程序集准备
a. 需要给项目添加 System.Web 程序集。
b. 需要给使用的地方添加两个引用。
2. 程序集探究
在对应的类中输入关键字 Cache,选中点击F12,查看Cache程序集,如下图所示:
我们一起来分析从上往下来分析一下该程序集。
(1). 两个字段,根据类型能看出来,一个是具体的时间点,另一个时间段,我们猜想,他们可能分别对应缓存中的绝对过期时间和相对过期时间。(其实事实也是如此)
(2). 构造函数
注意:通常我们实例化该类型的缓存,一般不直接通过构造函数实例化,我们通常使用 HttpRuntime.Cache 。我们一起来看看HttpRuntime的程序集,其中有个Cache属性,即可以通过它来获取Cache对象的实例。
(3). 顾名思义通俗易懂的属性和方法。
A : Count 属性,获取缓存个数。
B : Get(string key) 方法,根据缓存的键名来获取缓存的值。
C : Remove(string key) 方法,根据缓存的键名来删除缓存的值。
(4). 深究 public IDictionaryEnumerator GetEnumerator();
查看IDictionaryEnumerator的程序集,发现他是一个字典类型的集合,有键有值。
那么问题来了,怎么遍历该字典类型的集合呢?怎么获取对应的键和值呢?F12查看 IEnumerator程序集,发现里面有一个MoveNext()方法,可以推进到集合的下一个元素。
(5). Add和Insert方法,二者都为增加缓存的方法,而且二者最多参数的那个重载参数类型完全相同。不同的是Insert有多种重载方式,而Add只有一种重载。 二者核心差异:当缓存已经存在,用Add添加会报错,但用Insert添加,会直接覆盖更新。
下面以Add为例,一起来分析这七个参数。
A:key: 代表缓存的键名。
B:value:代表缓存的值,可以是任意类型。
C:dependencies:表示缓存的依赖项,可以依赖文件、文件夹、多个文件、以及依赖数据库,如果不需要依赖时,传入参数null。
D:absoluteExpiration:代表绝对过期时间,是个DateTime类型的时间点。如果要启用绝对过期时间,那么slidingExpriation必须为:Cache.NoSlidingExpiration。
该参数表现形式可以是:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00") 。
E:slidingExpiration:代表相对过期时间,是个TimeSpan类型的时间段。 如果要启用相对过期时间,那么absoluteExpiration必须为:Cache.NoAbsoluteExpiration。
该参数的表现形式可以是:: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒 。
F:priority:代表缓存销毁时的移除顺序,优先级低的先销毁。没有特殊要求通常使用: CacheItemPriority.Normal 即可。
G:onRemoveCallBack:是一个无返回值具有三个参数的委托。public delegate void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason);
当缓存过期时,调用该委托。委托的三个参数分别代表的含义为:缓存的键、缓存的值、缓存销毁的原因。
二[b]. 缓存封装[/b]
1. 封装思路
首先我们要清楚,封装的目的是什么? 说白了,方便自己、方便别人的灵活调用;同时便于以后的代码维护,能应对需求的变更。
通常调用的方式有两种:1. 将方法写成static静态方法,直接通过 类名.方法名 来进行调用。(该种方式偏离了面向对象的体系)
2. 将该类实例化,然后用实例化的对象调用该类中的封装方法。
3. 这里暂时不考虑 IOC的方式创建对象。
我们试想,会有什么需求变化呢? 有一天,PM要求,所有使用System.Web.Caching.Cache缓存的地方,都要改成 MemoryCache,如果我们事先没有应对措施,我的天!数不胜数的方法中均是传入的 Cache实例,不支持MemoryCache的实例,排着改?保证你崩溃!!!!!
上述场景,在实际开发中非常常见,解决该问题,我们通常使用DIP原则进行封装(依赖倒置原则,核心面向接口编程)。
所以我们定义一个缓存接口ICache,约束了缓存的定义的规范,然后我们再建立一个 RuntimeCacheHelp 类,对ICache进行了实现,同时也定义自己特有的方法。
2. 话不多说,直接上代码。
接口:
/// <summary> /// 定义缓存接口 /// </summary> public interface ICache { //1.缓存的个数只能获取,不能设置 int Count { get; } //2. 删除特定键的缓存 void Remove(string key); //3.移除全部缓存 void RemoveAll(); //4.根据键值获取特定类型的缓存 T Get<T>(string key); //5.判断缓存是否存在 bool Contains(string key); //6. 获取缓存值的类型 Type GetCacheType(string key); //7. 增加或更新缓存(存在则更新,不存在则添加,采用绝对时间的模式) /// <param name="cacheTime">绝对过期时间,默认1天</param> void AddOrUpdate(string key, object value,int cacheTime=1); }
缓存帮助类:
/// <summary> /// HttpRuntime缓存 /// 需要引入:System.Web程序集 /// 支持缓存依赖 /// </summary> public class RuntimeCacheHelp : ICache { //一.实例化的两种方式 #region 1.封装成属性 protected Cache cache { get { return HttpRuntime.Cache; } } #endregion #region 2.利用构造函数 //public Cache cache2 { get; set; } //public RuntimeCacheHelp() //{ // cache2 = HttpRuntime.Cache; //} #endregion //二. 实现接口中的方法 #region 1.获取缓存的个数 public int Count { get { return cache.Count; } } #endregion #region 2.删除特定键的缓存 /// <summary> /// 删除特定键的缓存 /// </summary> /// <param name="key">缓存的键名</param> public void Remove(string key) { cache.Remove(key); } #endregion #region 3.移除全部缓存 /// <summary> /// 移除全部缓存 /// </summary> public void RemoveAll() { IDictionaryEnumerator CacheEnum = cache.GetEnumerator(); while (CacheEnum.MoveNext()) { cache.Remove(CacheEnum.Key.ToString()); } } #endregion #region 4.根据键值获取特定类型的缓存 /// <summary> /// 根据键值获取特定类型的缓存 /// </summary> /// <typeparam name="T">泛型T</typeparam> /// <param name="key">键名</param> /// <returns></returns> public T Get<T>(string key) { //程序集中 this属性的应用 if (cache[key] != null) { return (T)cache[key]; } return default(T); } #endregion #region 5.判断缓存是否存在 /// <summary> /// 判断缓存是否存在 /// </summary> /// <param name="key">键值</param> /// <returns>true代表存在;false代表不存在</returns> public bool Contains(string key) { return cache.Get(key) == null ? false : true; } #endregion #region 6.获取缓存值的类型(子类创建) /// <summary> /// 获取缓存值的类型 /// </summary> /// <param name="key">键名</param> /// <returns>键名对应的缓存值的类型</returns> public Type GetCacheType(string key) { return cache[key].GetType(); } #endregion #region 7.增加或更新缓存(存在则更新,不存在则添加,采用绝对时间的模式) /// <summary> /// 增加或更新缓存 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="cacheTime">绝对过期时间,默认为1天</param> public void AddOrUpdate(string key, object value, int cacheTime = 1) { var absoluteTime = DateTime.Now + TimeSpan.FromDays(cacheTime); cache.Insert(key, value, null, absoluteTime, Cache.NoSlidingExpiration); } #endregion //三. 子类创建的新方法 #region 1.获取全部缓存(子类创建) public IDictionaryEnumerator GetAllCache() { IDictionaryEnumerator cacheList = cache.GetEnumerator(); //获取键值的方法 //while (cacheList.MoveNext()) //{ // var key = cacheList.Key.ToString(); // var value = cacheList.Value; //} return cacheList; } #endregion #region 2.Add模式增加缓存(子类创建) /// <summary> /// Add模式增加缓存(如果该缓存已经存在,再次添加会报错;Insert模式会覆盖上次) /// </summary> /// <param name="key">键</param> /// <param name="value">值</param> /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00");</param> /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param> /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写 /// false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写 /// </param> /// <param name="dependencies">缓存依赖:可以依赖文件、文件夹、数据库表</param> /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param> /// <param name="onRemoveCallback">缓存失效后的回调:含有三个参数的委托,三个参数分别为(key,value,reason) 即(缓存的键、值、失效原因)</param> public void AddCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, CacheDependency dependencies = null, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback onRemoveCallback = null) { if (isAbsolute) { //绝对过期 cache.Add(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration, priority, onRemoveCallback); } else { //相对过期 cache.Add(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback); } } #endregion #region 3.Insert模式增加缓存(子类创建) /// <summary> /// Insert模式增加缓存(如果该缓存已经存在,会覆盖上次,Add模式则是报错) /// </summary> /// <param name="key">键</param> /// <param name="value">值</param> /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00");</param> /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param> /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写 /// false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写 /// </param> /// <param name="dependencies">缓存依赖:可以依赖文件、文件夹、数据库表</param> /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param> /// <param name="onRemoveCallback">缓存失效后的回调:含有三个参数的委托,三个参数分别为(key,value,reason) 即(缓存的键、值、失效原因)</param> public void InsertCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, CacheDependency dependencies = null, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback onRemoveCallback = null) { if (isAbsolute) { //绝对过期 cache.Insert(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration, priority, onRemoveCallback); } else { //相对过期 cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback); } } #endregion
3. 如何调用?调用过程中会存在哪些问题?我们再后续章节中进行介绍。
相关文章推荐
- 第二节:从程序集的角度分析MemoryCache,并完成基本封装
- .net System.Web.Caching.Cache 缓存类使用详解
- System.Web.Caching.Cache
- asp.net 数据缓存System.Web.Caching.Cache 实例运用
- 用System.Web.Caching.Cache保存数据类的缓存
- System.Web.Caching.Cache删除某键后,希望同时触发其它动作(关键时刻,还是事件靠的住)
- .Net内部缓存System.Web.Caching.Cache 和Redis缓存缓存工厂切换
- 用System.Web.Caching.Cache保存数据类的缓存
- System.Web.Caching.Cache的简单介绍
- System.Web.Caching.Cache
- System.Web.Caching.Cache Web 缓存的使用
- System.Web.Caching.Cache
- 未能加载文件或程序集System.Web.Http.WebHost
- 未能加载文件或程序集 'System.Web.Extensions, Version=1.0.61025.0, ……
- CS0012: 类型“System.Web.Routing.RouteValueDictionary”在未被引用的程序集中定义。必须添加对程序集“System.Web.Routing, Version
- 学习和分享一点简单的System.Web.HttpRuntime.Cache的使用经验
- System.Net.WebException: 无法显示错误消息,原因是无法找到包含此错误消息的可选资源程序集
- System.Web.Caching
- System.Web.HttpContext.Current 跟踪分析
- 未能加载文件或程序集“System.Web.Helpers, Version=2.0.0.0