,,Asp.net Core 3.1基于AspectCore实现AOP实现事务、缓存拦截器功能

,,Asp.net Core 3.1基于AspectCore实现AOP实现事务、缓存拦截器功能

本文主要介绍Asp.net Core 3.1基于AspectCore的事务和缓存拦截器函数的AOP实现。这篇文章很详细,对你的学习或者工作有一定的参考价值。有需要的朋友可以参考一下。

最近想给自己的框架增加一个功能,就是比如给一个方法增加一个事务属性,那么这个方法就会启用事务处理。给一个方法添加一个缓存特性,这个方法就会缓存。

这也是面向方面编程的在线AOP。

AOP的概念也很好理解。它类似于中间件。说白了,我可以随意在方法前面或者后面添加代码,非常适合缓存、日志等处理。

我在net core2.2的时候,当时尝试用autofac实现aop,但是这次不想用autofac了。我用了一个更轻便的框架,AspectCore。

用起来非常非常简单,只是一开始走了一点弯路。主要是网core3以下的教程都在网上,3以下的用法和以前有些不同。

先安装NuGet包,包名:AspectCore。扩展。依赖注入

然后在Program.cs类中添加一行代码,这就是网芯3的区别。这个添加的代码意味着用AspectCore替换内置的IOC容器。因为AOP依赖IOC,所以内置的IOC必须更换。

公开课程

{

公共静态void Main(string[] args)

{

CreateHostBuilder(参数)。构建()。run();

}

公共静态IHostBuilder CreateHostBuilder(string[]args)=1

主持人。CreateDefaultBuilder(参数)。ConfigureWebHostDefaults(web builder=

{

webBuilder。UseStartupStartup();

})

//用AspectCore替换默认的IOC容器。UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());

}

然后在Startup.cs类的ConfigureServices中添加代码。(其实这个可以加,也可以不加。如果需要配置,可以添加,比如全局拦截器,只拦截哪些匹配的服务。因为我只用特性拦截,所以什么都没配置。)

服务。ConfigureDynamicProxy(o={

//添加AOP的配置

});

那么AOP配置好了,不是很简单吗?

当然,你也要注意使用。您可以截取接口、接口的方法、类和类的虚方法。而如果要拦截控制器的动作,则需要在ConfigureService中添加AddControllerAsServices。

服务。AddControllers()

//将控制器视为服务。AddControllersAsServices()

下面列出了我的事务拦截器代码。如果是特征拦截,我会继承AbstractInterceptorAttribute。如果我想写一个全局拦截器,我会抽象拦截器,然后在ConfigureDynamicProxy中配置它。这个我就不介绍了。

如果您的拦截器放在其他项目中,记得添加AspectCore。核心包,不仅仅是AspectCore。摘要。我只加了AspectCore。开头抽象,但是我一直没找到IsAsync,UnwrapAsyncReturnValue之类的一些扩展方法。

公共类TransactionInterceptorAttribute:AbstractInterceptorAttribute

{

公共异步重写任务调用(AspectContext上下文,下一个AspectDelegate)

{

var dbContext=context。service provider . GetServiceAppDbContext();

//先判断事务是否已经启用。

if (dbContext。database . current transaction==null)

{

等待dbContext。database . BeginTransactionAsync();

尝试

{

等待下一个(上下文);

dbContext。database . commit transaction();

}

catch(例外ex)

{

dbContext。database . roll back transaction();

扔ex;

}

}

其他

{

等待下一个(上下文);

}

}

}

然后我就可以如此优雅地使用事务了。

我再列出我的缓存拦截器,(感谢网友的提醒,我做了一下修改,针对异步方法返回值的处理),对了,下面的ICacheHelper是我定义的一个缓存助手接口,用的是redis,我会在后面写一篇博客

公共类CacheInterceptorAttribute:AbstractInterceptorAttribute

{

///摘要

///缓存秒数

////摘要

public int ExpireSeconds { get设置;}

公共异步重写任务调用(aspect上下文上下文,下一个AspectDelegate)

{

//判断是否是异步方法

bool isAsync=上下文isa sync();

//如果(上下文实现方法。GetCustomAttribute(类型为(AsyncStateMachineAttribute))!=空)

//{

//is async=true;

//}

//先判断方法是否有返回值,无就不进行缓存判断

var methodReturnType=上下文GetReturnParameter().类型;

if(method returntype==类型(void)| | method returntype==类型(任务)| | method returntype==类型(值任务))

{

等待下一个(上下文);

返回;

}

var returnType=方法returnType;

if (isAsync)

{

//取得异步返回的类型

returnType=returnType .GenericTypeArguments。FirstOrDefault();

}

//获取方法参数名

string param=CommonHelper .ObjectToJsonString(上下文。参数);

//获取方法名称,也就是缓存键值

string key='Methods:' context .实现方法。声明类型。全名。'语境ImplementationMethod。名字

var缓存=上下文服务提供商。GetServiceICacheHelper();

//如果缓存有值,那就直接返回缓存值

如果(缓存HashExists(key,param))

{

//反射获取缓存值,相当于缓存HashGet(key,param)

var value=typeof(ICacheHelper).GetMethod(nameof(ICacheHelper .HashGet)).MakeGenericMethod(returnType).Invoke(cache,new[] { key,param });

if (isAsync)

{

//判断是工作还是价值任务

if(method returntype==任务类型).MakeGenericType(returnType))

{

//反射获取工作类型的返回值,相当于任务。来自结果(值)

语境ReturnValue=typeof(任务)。获取方法(任务的名称FromResult)).MakeGenericMethod(returnType).Invoke(null,new[] { value }).

}

else if(method returntype==type of(value task).MakeGenericType(returnType))

{

//反射构建价值任务类型的返回值,相当于新值任务(值)

语境ReturnValue=激活器创建实例(值任务的类型).MakeGenericType(returnType),value);

}

}

其他

{

语境ReturnValue=值;

}

返回;

}

等待下一个(上下文);

对象返回值;

if (isAsync)

{

返回值=等待上下文unwapasyncreturnvalue();

//反射获取异步结果的值,相当于(上下文。返回值作为任务)。结果

//returnValue=typeof(Task).MakeGenericType(returnType).GetProperty(nameof(Taskobject .结果))。GetValue(上下文return value);

}

其他

{

返回值=上下文ReturnValue

}

缓存HashSet(key,param,返回值);

if (ExpireSeconds 0)

{

缓存SetExpire(key,TimeSpan .从秒(过期秒));

}

}

}

我还弄了一个缓存删除拦截器,作用就是带有这个特性的方法执行后,会删除相关缓存值

为什么有这个设计呢,比如说我给一个方法GetUserList加了缓存,那我数据改变了怎么办,我想在用户数据改变时,把这个缓存删除掉,那我就可以在保存用户方法上加上我这个缓存删除拦截器,那这个方法执行后,就会把相关的缓存删除掉了

公共类CacheDeleteInterceptorAttribute:AbstractInterceptorAttribute

{

私有只读类型[]_类型;

私有只读字符串[]_方法;

///摘要

///需要传入相同数量的类型和方法,相同位置的类型和方法会组合成一个缓存键进行删除。

////摘要

///param name='Types '在类中传递以删除缓存/param

///param name='Methods '传入的用于删除缓存的方法的名称必须对应于类型array/param

公共CacheDeleteInterceptorAttribute(Type[]类型,string[]方法)

{

如果(类型。长度!=方法。长度)

{

抛出新的apifailexception (apifailcode。operation _ fail,'类型必须与方法数相同');

}

_types=类型;

_methods=方法;

}

公共异步重写任务调用(AspectContext上下文,下一个AspectDelegate)

{

var cache=上下文。service provider . GetServiceICacheHelper();

等待下一个(上下文);

for(int I=0;I _类型。长度;我)

{

var type=_ types[I];

var method=_ methods[I];

string key='Methods:' type。全名“.”方法;

缓存。删除(键);

}

}

}

我还想象了AOP的实现原理:

要实现AOP,我们需要依靠IOC容器,因为它是我们类的管家。可以拦截的类必须是IOC注入的,自己新出来的不拦截。如果我想在方法A前面添加一些代码,我会告诉IOC把代码给它。IOC注入方法A的类时,会继承它生成一个派生类,然后重写方法A,所以拦截方法必须是虚的,那么我要添加的代码就写在方法A中,然后是base。一个()是这样的。

关于Asp.net核心3.1基于AspectCore实现AOP事务和缓存拦截器功能的文章到此结束。有关Asp.net核心3.1实现事务和缓存拦截器的更多信息,请搜索我们以前的文章或继续浏览以下相关文章。希望大家以后能多多支持我们!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: