封装System.Runtime.Caching.MemoryCache实现服务端缓存,以及在依赖注入中使用时要注意的坑

封装System.Runtime.Caching.MemoryCache,利用其静态对象System.Runtime.Caching.MemoryCache.Default的Get,Set等方法实现服务端缓存。

需要注意的是,

假如封装的缓存对象固定是MemoryCache.Default(比如以下CoreMemoryCache的封装,实现自定义的ICache接口),并且该封装对象通过依赖注入产生,那么这里有个奇怪现象需要注意: 假如是通过

  • “container.RegisterInstance(typeof(ICache),名字或null,MemoryCache封装对象”
  • “container.RegisterInstance〈ICache〉(MemoryCache封装对象)”

注册实例,则后面不可以再重复再注册ICache,包括不能重复执行两次相同的RegisterInstance〈ICache〉语句,
不然,Resolve之后,会造成明明已经通过Set方法设置了缓存,接着Get方法得到却是null,并且无给出异常信息的坑!(这是哪怕再用new来创建一个新的“MemoryCache封装对象”来进行操作也会存在这样的问题)。

但是如果通过“container.RegisterType〈ICache,MemoryCache封装类〉([可以是单例的生命周期])”注册类依赖类型,
那么,在未Resolve之前,可以重复多次执行“container.RegisterType〈ICache,MemoryCache封装类〉()”注册,甚至最后可以再有但只能有一次的“container.RegisterInstance〈ICache〉(MemoryCache封装对象)”,因为在未有真正对象实际产生之前,注册类型相当于只是一种关系映像声明,同类型相同name参数的注册声明只有最后一次更新有效,但一旦通过RegisterInstance,或者对RegisterType类型的Resolve,将注册类型与一个具体的“MemoryCache封装对象实例”绑定,那么在这个MemoryCache封装实例对象的注册类型生命周期完结之前不可以再为注册的类型(这里指ICache类型)重复绑定,不然就会出现Cache执行完Set操作还是无Item的奇怪问题,这时哪怕再new一个“MemoryCache封装对象实例”出来操作也一样有此问题!

总结来说,就是
在Unity容器中,RegisterInstance或者已经Resolve过的单例生命周期的RegisterType,“注册类型(这里的ICache)”已经绑定或解析出一个具体的“MemoryCache封装类的对象”,那么在此对象的生命周期内(直接绑定了对象类似单例)不能重复再为“注册类型(这里的ICache)”注册另一个或者同一个“MemoryCache封装类的对象”,否则就会出现前面所说的Set了Item却无法生成Item记录的奇怪问题。

举以下实践过的例子来说明:

  1. container.RegisterType〈ICache,CoreMemoryCache〉(null,new SingletonLifetimeManager());
    var _cache = container.Resolve(typeof(ICache)); //由于前面注册的是单例生命周期,在此并未完结
    container.RegisterType〈ICache,CoreMemoryCache〉();
    var _cache2 = container.Resolve(typeof(ICache));

以上代码会存在前面提到的缓存Set无效的问题,但假如把两个注册语句顺序对调一下就不存在此问题了,如下:

  1. container.RegisterType〈ICache,CoreMemoryCache〉();
    var _cache = container.Resolve(typeof(ICache)); //由于前面注册类型的是默认的短暂生命周期 TransientLifetimeManager,下一次Resolve解析新的实例时,这里生成的这一次的对象的生命周期结束,因此并不是在一个生命周期之内再将ICache类型通过改变了的绑定生成另一个具体对象,因此不会出现上面提到的问题
    container.RegisterType〈ICache,CoreMemoryCache〉(null,new SingletonLifetimeManager());
    var _cache2 = container.Resolve(typeof(ICache)); //这里之后才不能再为ICache注册“MemoryCache封装类”的“生成类”或对象

  2. 但反过来,同一个“MemoryCache封装类的对象”或者生成对象的生命周期内,有另一个注册类型关联同一个“生成类型”或同一个“MemoryCache封装类的对象”,这种情况并不影响,不会出现上述问题,比如“MemoryCache封装类”CoreMemoryCache同时还实现另一个接口IAnotherCache,以下代码不会出现前述的问题:
    A.有另一个注册类型关联同一个“生成类型”:
    container.RegisterType〈ICache,CoreMemoryCache〉(null,new SingletonLifetimeManager());
    var _cache = container.Resolve(typeof(ICache));
    //同时与ICache,又与IAnotherCache类型注册绑定,两者并不冲突,无上述问题
    container.RegisterType〈IAnotherCache,CoreMemoryCache〉(null,new SingletonLifetimeManager());
    var _cache2 = container.Resolve(typeof(IAnotherCache));
    B.有另一个注册类型关联同一个“MemoryCache封装类的对象”:
    var memCacheInstance = new CoreMemoryCache();
    container.RegisterInstance(typeof(ICache), null, memCacheInstance);
    var _cache = container.Resolve(typeof(ICache));
    //同时与ICache,又与IAnotherCache类型注册绑定,两者并不冲突,无上述问题
    container.RegisterInstance(typeof(IAnotherCache), null, memCacheInstance);
    var _cache2 = container.Resolve(typeof(IAnotherCache));

注意:这个问题只是Unity依赖注入中使用MemoryCache相关类才有的问题,可能由于该类使用的是内存缓存这样的特殊机制,以及在依赖注入不同于new的地方,才刚好会有这样的坑,并不是其他类型在使用依赖注入会遇到的问题。不是通性的知识

以下是“MemoryCache封装类”的部分代码:
public class CoreMemoryCache:ICache
{
private readonly ObjectCache _cache;
public CoreMemoryCache()
{
_cache = MemoryCache.Default;
}
public T Get〈T〉(string key)
{
return (T) _cache.Get(key);
}
public T Set〈T〉(string key, T item)
{
_cache.Set(key, item, DataTimeOffset.MaxValue);
}
…………//Get,Set,Contains,Remove,Clear等等实现对MemoryCache.Default操作的封装方法
}

封装对MemoryCache.Default操作实现服务端缓存操作
封装对MemoryCache.Default操作实现服务端缓存操作

.Net提供的MemoryCache类组件
.Net提供的MemoryCache类组件

おすすめ

転載: blog.csdn.net/carcarrot/article/details/118734628