.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缓存的实现中,通过缓存整个方法的返回是不是一个好的解决方案,在一些特殊的业务场景中如果这个方法返回是一个复杂的类型 是否会有异常?如果不通过缓存整个方法返回 是否还有什么更好的解决方案? 如果各位大神有更好的解决方案,还请多多指教,现在这里感谢了。
来源:oschina
链接:https://my.oschina.net/u/4279909/blog/4325377