.Net core+Reds如何实现Aop缓存
前言
在实际开发的场景中,有很多需要缓存的数据,为了减少重复代码的编写,想采用Aop的方式来实现切面编程减少对以有业务代码的改动和侵入性。
在传统的 .Net Framework项目中实现Aop有很多简单的方式,但是在 .Net Core中尤其是1.X版本笔者没有找到比较好的解决方案采用了一个三方开源的Aop库,下面会写出来。
准备
本次采用的环境是 .Net Core 1.1版本
本次使用的Aop 开源库是 AspectCore 0.1.2版本
实践
Aop顾名思义面向切面编程,是一种通过预编译和运行时动态代理来实现的一种技术,本文中采用了三方开源的Aop库 AspectCore 是.Net Core 中一个轻量级和模块化的Aop 解决方案
首先创建一个 缓存特性 CacheAttribute 继承 AspectCore中的 InterceptorAttribute并且重写 InterceptorAttribute中的 Invoke方法 代码 如下
1 public async override Task Invoke(AspectContext context, AspectDelegate next) 2 { 3 try 4 { 5 //用方法名称+入参 生成Key 6 string key = context.Proxy.ProxyMethod.Name; 7 foreach (var item in context.Parameters) 8 { 9 key += item.Value; 10 } 11 //判断缓存是否已经存在 12 var isExists = await RedisCache.ExistsAsync(key); 13 if (!isExists) 14 { 15 //如果不存在缓存 则执行方法 并且缓存方法返回值 16 await next(context); 17 await RedisCache.SetAsync(key, JObject.FromObject(context.ReturnParameter.Value).ToString(), Timeout); 18 } 19 else 20 { 21 var result = RedisCache.Get(key); 22 if (_type != null) 23 { 24 //判断是否异步返回类型 因为异步方法无法正常转换 需要先取返回后 在异步化 25 dynamic info = JObject.Parse(result).ToObject(_type); 26 context.ReturnParameter.Value = Task.FromResult(info.Result); 27 } 28 else 29 context.ReturnParameter.Value = JObject.Parse(result).ToObject(context.ReturnParameter.ParameterType); 30 } 31 } 32 catch (Exception ex) 33 { 34 //Aop异常 直接跳过Aop 进入方法 35 await next(context); 36 } 37 }
上面的代码展示了 如何使用AspectCore结合Redis实现Aop缓存,在实现的过程中笔者发现,异步方法没有办法通过Json正常的转换,所以先通过取值在进行异步化,如果有哪位大神有好的解决方案还请告知一二(十分感谢),同步方法没有问题可以正常Json和转换。
实现了核心的Aop的代码最后使用的时候 很简单代码如下几种情况
1.同步方法
1 public interface ITestService 2 { 3 [Cache] 4 Test Show(); 5 }
2.异步方法
1 public interface ITestService 2 { 3 [Cache(typeof(Parameter<Test>))] 4 Task<Test> Show(string input); 5 }
只要在接口的方法上标上Cache 特性即可实现对现有业务无入侵的改造
思考
在这次实现Aop 的过程中,笔者一直有个疑问在Aop缓存的实现中,通过缓存整个方法的返回是不是一个好的解决方案,在一些特殊的业务场景中如果这个方法返回是一个复杂的类型 是否会有异常?如果不通过缓存整个方法返回 是否还有什么更好的解决方案? 如果各位大神有更好的解决方案,还请多多指教,现在这里感谢了。