一、基本使用
首先需要定义一个Action过滤器类,如命名为:MyActionFilter,继承IActionFilter(同步)或IAsyncActionFilter(异步)接口,这里以IAsyncActionFilter为例,如图:
然后在Program.cs中注册自定义的Action过滤器:
1 2 3 4 |
|
控制台输出如下:
如果添加多个Action过滤器呢? 效果是什么样的?这里添加了三个Action过滤器
1 2 3 4 5 6 |
|
MyActionFilter2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
MyActionFilter3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
执行效果如下:
二、自动启用事物的ActionFilter过滤器
实现:
1.自定义注解
[AttributeUsage(AttributeTargets.Method)]
public class NotTransactionalAttribute : Attribute
{
}
2.自动启用事务的筛选器
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;
using System.Transactions;
namespace 自动启用事务的筛选器
{
public class TransactionScopeFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
bool hasNotTransactionalAttribute = false;
if (context.ActionDescriptor is ControllerActionDescriptor)
{
var actionDesc = (ControllerActionDescriptor)context.ActionDescriptor;
hasNotTransactionalAttribute = actionDesc.MethodInfo
.IsDefined(typeof(NotTransactionalAttribute));
}
if (hasNotTransactionalAttribute)
{
await next();
return;
}
using var txScope =
new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var result = await next();
if (result.Exception == null)
{
txScope.Complete();
}
}
}
ActionDescriptor的作用是对Action方法的元数据的描述,通过ActionDescriptor我们可以获取到action方法的相关的名称,所属控制器,方法的参数列表,应用到方法上的特性以及一些筛选器;ActionDescriptor是由ControllerDescriptor类中的FindAction方法进行创建;
ActionDescriptor类也继承了ICustomAttributeProvider接口,所以ActionDescriptor类或是它的继承类也实现了GetCustomAttributes和IsDefined方法;
ActionDescriptor类中的属性和ControllerDescriptor类的属性差不多,包含有一个含有描述操作符唯一性ID的 UniqueId,表示方法名称的ActionName以及action所属于的控制器的元数据描述类ControllerDescriptor等属性字段;为了加快action方法的执行效率,ActionDescriptor类内部还创建了一个action方法调度的缓存属性(ActionMethodDispatcherCache )DispatcherCache;
ActionMethodDispatcherCache 这个类结构是key为MethodInfo value 为ActionMethodDispatcher的字典缓存,在这个缓存类中通过GetDispatcher方法来快速获取ActionMethodDispatcher类;
在.NET 4.0(当然也包括4.0以前的版本)下,用反射判断某个方法是否运用了自定义Attribute时,可以通过调用MethodInfo的IsDefined()方法进行确认。当然,IsDefined()方法事实上定义在MethodInfo的父类MemberInfo中,但它仅仅被定义为抽象方法,真正的实现是在MethodInfo的子类DynamicMethod中
3.注册
builder.Services.Configure<MvcOptions>(options =>
{
options.Filters.Add<TransactionScopeFilter>();
});