Action过滤器(ActionFilter)

一、基本使用

首先需要定义一个Action过滤器类,如命名为:MyActionFilter,继承IActionFilter(同步)或IAsyncActionFilter(异步)接口,这里以IAsyncActionFilter为例,如图:

然后在Program.cs中注册自定义的Action过滤器:

1

2

3

4

builder.Services.Configure<MvcOptions>(options => {

    //注册自定义的Actioin过滤器

    options.Filters.Add<MyActionFilter>();

});

控制台输出如下:

如果添加多个Action过滤器呢? 效果是什么样的?这里添加了三个Action过滤器

1

2

3

4

5

6

builder.Services.Configure<MvcOptions>(options => {

    //注册自定义的Actioin过滤器

    options.Filters.Add<MyActionFilter>();

    options.Filters.Add<MyActionFilter2>();

    options.Filters.Add<MyActionFilter3>();

});

MyActionFilter2:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class MyActionFilter2 : IAsyncActionFilter

    {

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

        {

            Console.WriteLine("MyActionFilter2 Begin");

            //执行真正要执行的Action

            ActionExecutedContext nextContext = await next();

            //通过Exception判断Action是否执行成功

            if (nextContext.Exception != null)

                Console.WriteLine("Action执行异常!");

            else

                Console.WriteLine("Action执行成功!");

            Console.WriteLine("MyActionFilter2 End");

        }

    }

MyActionFilter3:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class MyActionFilter3 : IAsyncActionFilter

    {

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

        {

            Console.WriteLine("MyActionFilter3 Begin");

            //执行真正要执行的Action

            ActionExecutedContext nextContext = await next();

            //通过Exception判断Action是否执行成功

            if (nextContext.Exception != null)

                Console.WriteLine("Action执行异常!!");

            else

                Console.WriteLine("Action执行成功!!");

            Console.WriteLine("MyActionFilter3 End");

        }

    }

执行效果如下:

二、自动启用事物的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>();

});

猜你喜欢

转载自blog.csdn.net/weixin_57062986/article/details/131851522
今日推荐