Asp.net使用快取 (二)

前篇-Asp.net使用快取 (一)向大家简单介绍

快取是什么为何要使用快取使用简单HttpRuntime.Cache使用快取机制

这篇是分享把快取程式码变得更有弹性


第二篇大纲

提出介面,提高可替换性使用泛型改写快取 读取方式使用扩充方法改写快取
提出介面,提高可替换性

情境:

目前有个专案使用 HttpRuntime.Cache 物件

在记忆体快取中除了使用 Asp.Net 中HttpRuntime.Cache类别外还有很多解决方案.例如使用Memcache,Redis...

如果我们原本使用HttpRuntime.Cache类别但之后要转成其他快取方式怎么办?

public class HomeController : Controller{System.Web.Caching.Cache cacheContainer = HttpRuntime.Cache;public ActionResult Index(){string cacheData = cacheContainer.Get("data") as string;if (cacheData==null){cacheContainer.Insert("test1", DateTime.Now.ToShortDateString());}  return View(cacheData);}}

虽然使用不同快取方式,但记得我上篇的重点快取会有两个动作,读和写,所以最基本就会有读和写这两个动作

OOP有个很重要的观念 多个类有重複动作考虑提出父类别

为了方便了解我把HttpRuntime.Cache封装成一个类别

public class NetCache {    System.Web.Caching.Cache cacheContainer = HttpRuntime.Cache;    public object GetCacheObject(string key) {        return cacheContainer.Get(key);    }    public void SetCache(string key,object obj) {        cacheContainer.Insert(key, obj);    }}

这边有另一个Memcache快取Class

public class MemeryCache {private ObjectCache _cache = MemoryCache.Default;public object GetCacheObject(string key){return _cache[cacheKey];}public void SetCache(string key, object obj){var policy = new CacheItemPolicy();policy.RemovedCallback = OnFileContentsCacheRemove;// 设定快取时间2分钟policy.AbsoluteExpiration = DateTimeOffset.Now.Minute(2);_cache.Set(cacheKey, fileContents, policy);}}

先不关注这两个物件里面细节,我们可以发现他们都有 GetCacheObject 方法和SetCache 方法

这时我们就可以适时提出介面(interface),当作这两个类别的合约

public interface ICache {void Set(string key,object obj);object Get(string key);}

之后将他们两个类别实现 ICache 介面

public class MemeryCache : ICache{private ObjectCache _cache = MemoryCache.Default;public object Get(string key){return _cache[cacheKey];}public void Set(string key, object obj){var policy = new CacheItemPolicy();policy.RemovedCallback = OnFileContentsCacheRemove;// 设定快取时间2分钟policy.AbsoluteExpiration = DateTimeOffset.Now.Minute(2);_cache.Set(cacheKey, fileContents, policy);}}public class NetCache : ICache{    System.Web.Caching.Cache cacheContainer = HttpRuntime.Cache;    public object Get(string key) {        return cacheContainer.Get(key);    }        public void Set(string key,object obj) {        cacheContainer.Insert(key, obj);    }}

提出介面有甚么好处?

我们可以把前面程式码改成IOC依赖注入的方式,不要在程式码写死使用HttpRuntime.Cache,由IOC容器帮我们把物件注入程式码中.

Note:我使用建构子注入法

public class HomeController : Controller{    //不用写死使用  HttpRuntime.Cache//System.Web.Caching.Cache cacheContainer = HttpRuntime.Cache;    ICache cacheContainer;    public HomeController(ICache Container){        cacheContainer = Container;    }    public ActionResult Index(){string cacheData = cacheContainer.Get("data") as string;if (cacheData==null){cacheContainer.Insert("test1", DateTime.Now.ToShortDateString());}  return View(cacheData);}}

ICache 变成快取程式码的润滑剂.可让程式变得更有弹性


使用泛型改写快取 读取方式

我在StackOverFlow解答的方式就是第二种

其中最主要的技巧就是把Get方法返回的Object改成使用泛型

 public T GetOrSetCache<T>    (string key,T obj, int cacheTime) where T:class,new(){    System.Web.Caching.Cache cacheContainer = HttpRuntime.Cache;    T cacheObj = cacheContainer.Get(key) as T;    if (cacheObj == null)    {        cacheContainer.Insert(key,            obj,            null,             DateTime.Now.AddMinutes(cacheTime),            System.Web.Caching.Cache.NoSlidingExpiration);        cacheObj = obj;    }    return cacheObj;}

让我们在使用时可以变成

var data = DateTime.Now.ToShortDateString();int numberOfMinutes = 3;data = GetOrSetCache("name1",data,numberOfMinutes );

我们只需要呼叫GetOrSetCache方法,这个方法把GetCacheSetCache封装起来了


使用扩充方法改写快取

.Net有提供一个很方便的机制 扩充方法,这个机制帮我们解决一个很重要的问题.
我们可以扩充已经封装但没有原始码的类别,

在这段程式码中,使用Func<TObj> 可以使用lambda 表达式,让程式码更简洁有力!!

public static TObj GetOrSetCache<TObj>(this Func<TObj> selector, string key, int cacheTime)    where TObj : class{ Cache cacheContainer = HttpRuntime.Cache;//get cache Objectvar obj = cacheContainer.Get(key) as TObj;//if there isn't cache object add this object to cacheif (obj == null){obj = selector();cacheContainer.Insert(key, obj);}return obj;}

我们使用时如下

变更简洁动作更漂亮

int numberOfMinutes = 3;data = GetOrSetCache(()=> DateTime.Now.ToShortDateString(),"name1",data,numberOfMinutes );

同场加映:

扩展方法和介面搭配使用

public class WebDefaultCache : ICache{Cache cacheContainer = HttpRuntime.Cache;public object Get(string key){return cacheContainer.Get(key);}public void Set(string key, object obj){cacheContainer.Insert(key, obj);}}public interface ICache{void Set(string key, object obj);object Get(string key);}public static class InfrastructureExtension{public static TObj GetOrSetCache<TObj>(this Func<TObj> selector, string key) where TObj : class {return GetOrSetCache(selector, key,10);}public static TObj GetOrSetCache<TObj>(this Func<TObj> selector, string key, int cacheTime) where TObj : class{return GetOrSetCache(selector, key, cacheTime, new WebDefaultCache());}public static TObj GetOrSetCache<TObj>(this Func<TObj> selector, string key, int cacheTime, ICache cacheContainer) where TObj : class{//get cache Objectvar obj = cacheContainer.Get(key) as TObj;//if there isn't cache object add this object to cacheif (obj == null){obj = selector();cacheContainer.Set(key, obj);}return obj;}}

虽然在使用上和第三种一样
但我们多了使用方法重载多传一个参数ICache介面 可以让我们在写程式时决定要使用哪种cache方式,不用改快去那边程式码.

同场加映程式码我放在我自己常用的ExtenionTool专案中


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章