当前位置 : 主页 > 网络编程 > ASP >

Asp.net使用缓存 (二)

来源:互联网 收集:自由互联 发布时间:2021-06-24
前篇-Asp.net使用缓存 (一)向大家简单介绍 缓存是什么 为何要使用缓存 使用简单 HttpRuntime.Cache 使用缓存机制 这篇是分享把缓存程序变得更有弹性 第二篇大纲 提出界面,提高可替换性 使

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

  1. 缓存是什么
  2. 为何要使用缓存
  3. 使用简单HttpRuntime.Cache使用缓存机制

这篇是分享把缓存程序变得更有弹性


第二篇大纲

  1. 提出界面,提高可替换性
  2. 使用泛型改写缓存 读取方式
  3. 使用扩充方法改写缓存

  1. 提出界面,提高可替换性

情境:

目前有个项目使用?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?变成缓存程序的润滑剂.可让程序变得更有弹性


  1. 使用泛型改写缓存 读取方式

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

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

public T GetOrSetCache
  

 
  
  (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封装起来了


  1. 使用扩充方法改写缓存

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

在这段程序中,使用Func ?可以使用lambda?表达式,让程序更简洁有力!!

public static TObj GetOrSetCache
  

 
  
  (this Func 
 
  
    selector, string key, int cacheTime) where TObj : class { Cache cacheContainer = HttpRuntime.Cache; //get cache Object var obj = cacheContainer.Get(key) as TObj; //if there isn‘t cache object add this object to cache if (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
  

 
  
  (this Func 
 
  
    selector, string key) where TObj : class { return GetOrSetCache(selector, key,10); } public static TObj GetOrSetCache 
   
     (this Func 
    
      selector, string key, int cacheTime) where TObj : class { return GetOrSetCache(selector, key, cacheTime, new WebDefaultCache()); } public static TObj GetOrSetCache 
     
       (this Func 
      
        selector, string key, int cacheTime, ICache cacheContainer) where TObj : class { //get cache Object var obj = cacheContainer.Get(key) as TObj; //if there isn‘t cache object add this object to cache if (obj == null) { obj = selector(); cacheContainer.Set(key, obj); } return obj; } } 
       
      
     
    
   

 

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

同场加映程序我放在我自己常用的ExtenionTool项目中


如果本文对您帮助很大,可街口支付斗内鼓励石头^^

原文:大专栏  Asp.net使用缓存 (二)

网友评论