在任何框架中,缓存都是不可或缺的一部分,本框架亦然。在这个框架中,我们的缓存分为两部分:内存缓存和单次请求缓存。简单说来,就是一个使用微软提供的MemoryCache做扩展,并提供全局唯一实例;另一个使用微软提供的HttpContextBase做扩展,用户每发送一次请求,HttpContextBase都会被关联创建。先来看下接口约束:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: 6: namespace TinyFrame.Framework.Caching
7: { 8: public interface ICacheManager
9: { 10: //根据key获取缓存对象
11: T Get<T>(string key);
12: 13: //设置缓存对象
14: void Set(string key, object data, int cacheTime);
15: 16: //查询key是否被缓存
17: bool IsSet(string key);
18: 19: //从缓存移除
20: void Remove(string key);
21: 22: //缓存移除匹配
23: void RemoveByPattern(string pattern);
24: 25: //清空所有缓存
26: void Clear();
27: } 28: }
方法不多,但是包含了缓存的增删查。其中Get泛型方法可以通过Key返回缓存对象;Set方法可以添加缓存;IsSet方法可以检测缓存是否存在;Remove方法可以清除已有的单个缓存;RemoveByPattern可以通过正则匹配清除缓存;Clear方法则清除全部缓存。
首先是MemoryCacheManager的实现:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Runtime.Caching;
6: using System.Text.RegularExpressions;
7: 8: namespace TinyFrame.Framework.Caching
9: { 10: public class MemoryCacheManager:ICacheManager
11: { 12: protected ObjectCache Cache
13: { 14: get { return MemoryCache.Default; }
15: } 16: 17: public T Get<T>(string key)
18: { 19: return (T)Cache[key];
20: } 21: 22: public void Set(string key, object data, int cacheTime)
23: { 24: if (data == null)
25: return;
26: var policy = new CacheItemPolicy();
27: policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime); 28: Cache.Add(new CacheItem(key,data),policy);
29: 30: } 31: 32: public bool IsSet(string key)
33: { 34: return Cache.Contains(key);
35: } 36: 37: public void Remove(string key)
38: { 39: Cache.Remove(key); 40: } 41: 42: public void RemoveByPattern(string pattern)
43: { 44: var regex = new Regex(pattern, RegexOptions.Singleline
45: | RegexOptions.Compiled 46: | RegexOptions.IgnoreCase); 47: var keysToRemove = new List<string>();
48: foreach (var item in Cache)
49: if (regex.IsMatch(item.Key))
50: keysToRemove.Add(item.Key); 51: 52: foreach (string key in keysToRemove)
53: { 54: Remove(key); 55: } 56: } 57: 58: public void Clear()
59: { 60: foreach (var item in Cache)
61: { 62: Remove(item.Key); 63: } 64: } 65: } 66: }
然后是PerRequestCacheManager的实现:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Web;
6: using System.Collections;
7: using System.Text.RegularExpressions;
8: 9: namespace TinyFrame.Framework.Caching
10: { 11: public class PerRequestCacheManager : ICacheManager
12: { 13: public PerRequestCacheManager(HttpContextBase context)
14: { 15: this.context = context;
16: } 17: 18: private readonly HttpContextBase context;
19: 20: protected virtual IDictionary GetItems()
21: { 22: if (context != null)
23: return context.Items;
24: 25: return null;
26: } 27: 28: public T Get<T>(string key)
29: { 30: var items = GetItems(); 31: if (items == null)
32: return default(T);
33: 34: return (T)items[key];
35: } 36: 37: public void Set(string key, object data, int cacheTime)
38: { 39: var items = GetItems(); 40: if (items == null)
41: return;
42: 43: if (data != null)
44: { 45: if (items.Contains(key))
46: items[key] = data; 47: else
48: items.Add(key, data); 49: } 50: } 51: 52: public bool IsSet(string key)
53: { 54: var items = GetItems(); 55: if (items == null)
56: return false;
57: 58: return items[key] != null;
59: } 60: 61: public void Remove(string key)
62: { 63: var items = GetItems(); 64: if (items == null)
65: return;
66: 67: items.Remove(key); 68: } 69: 70: public void RemoveByPattern(string pattern)
71: { 72: var items = GetItems(); 73: if (items == null)
74: return;
75: 76: var enumerator = items.GetEnumerator(); 77: var regex = new Regex(pattern, RegexOptions.Singleline
78: | RegexOptions.Compiled 79: | RegexOptions.IgnoreCase); 80: var keysToRemove = new List<string>();
81: while (enumerator.MoveNext())
82: { 83: if (regex.IsMatch(enumerator.Key.ToString()))
84: { 85: keysToRemove.Add(enumerator.Key.ToString()); 86: } 87: } 88: 89: foreach (string key in keysToRemove)
90: { 91: items.Remove(key); 92: } 93: } 94: 95: public void Clear()
96: { 97: var items = GetItems(); 98: if (items == null)
99: return;
100: 101: var enumerator = items.GetEnumerator(); 102: var keysToRemove = new List<string>();
103: while (enumerator.MoveNext())
104: { 105: keysToRemove.Add(enumerator.Key.ToString()); 106: } 107: 108: foreach (string key in keysToRemove)
109: { 110: items.Remove(key); 111: } 112: } 113: } 114: }
二者的实现方式差不多。这里我就不做过多的解释了。
如果想使用的话,直接在Autofac容器中注册一下就行了。在这次演示中,我们使用MemoryCacheManager来做缓存容器。
这里我以一个分页为例:
1: string BookPaggerKey = "Books-{0}-{1}-{2}-{3}";
2: //分页查询
3: public IList<Book> GetBooksPagger(int pageCount
4: , int currentIndex
5: , out int totalCount
6: , string propertyName=""
7: , string propertyValue=""
8: ) 9: { 10: IQueryable<Book> bookList = null;
11: int skipRows = 0;
12: if (currentIndex > 0) skipRows = currentIndex * pageCount;
13: 14: if (!string.IsNullOrEmpty(propertyName))
15: bookList = GetBooksByConstruct(propertyName, propertyValue); 16: else
17: bookList = bookRepository.GetMany(m => m.ID >= 0); 18: totalCount = bookList.Count(); 19: 20: //return bookList.OrderBy(p => p.ID).Skip(skipRows).Take(pageCount).ToList();
21: string key = string.Format(BookPaggerKey, pageCount, currentIndex, propertyName, propertyValue);
22: 23: return cacheManager.Get(key, () => bookList.OrderBy(p => p.ID).Skip(skipRows).Take(pageCount).ToList());
24: } 第1行:定义了一个Cache的Key,用于标识保存ID
第23行:利用get方法检查缓存容器,如果缓存中数据不存在,则将查询数据添加到缓存;否则直接从缓存中拿出数据来。
我们来看看效果:
首先打开页面,我们换换页,目的是让页面被缓存住:

然后我们打开SQL的SQL Server Profile来进行追踪,现在,我们点击页面的刷新按钮,看看测试效果 :

当我们连续刷新页面好几次,但是并未见到有新的分页查询被追踪到,说明我们的数据被缓存住了。
最后我们加个断点调试一下缓存对象,可以找到被缓存的数据:
