ASP.Net Core的Filter

文章目录

  • 一、什么是Filter?
  • 二、Exception filter
  • 三、Action filter
  • 四、实现一个自动启用事务的Action Filter


一、什么是Filter?

  • 切面编程机制,在ASP.Net Core特定的位置执行我们的自定义代码

  • ASP.NET Core中有Filter的五种类型:

    • Authorization filter(权限验证)
    • Resource filter(资源缓存)
    • Action filter(模型验证/日志记录)
    • Exception filter(异常捕获)
    • Result filter(处理返回结果)
  • 所有筛选器一般有两个版本,比如IActionFilterIAsyncActionFilter


二、Exception filter

当系统中出现未经处理的异常的时候,异常筛选器就会执行

  1. 新建一个API控制器TestController

  2. 在控制器中编写一个会抛异常的方法,代码如下:

    [HttpGet]
    public string Test1()
    {
    	string s = System.IO.File.ReadAllText("D:1.txt");
    	return s;
    }
    
  3. 调用方法Test1后,会出现以下界面
    ASP.Net Core的Filter_第1张图片

  4. 当系统中出现未处理异常的时候,假设我们需要统一返回给客户端一个如下格式的响应报文:{"code":"500","message":"异常信息"},可以通过一个实现了IAsyncExceptionFilter接口的类来实现,类的代码如下:

    public class MyExceptionFilter : IAsyncExceptionFilter
    {
        private readonly IWebHostEnvironment webHost;
    
        public MyExceptionFilter(IWebHostEnvironment webHost)
        {
            this.webHost = webHost;
        }
    
        public Task OnExceptionAsync(ExceptionContext context)
        {
            string message;
            if (webHost.IsDevelopment())
            {
                message = context.Exception.ToString(); //context.Exception 代表异常信息对象
            }
            else
            {
                message = "服务器端发生未处理异常!";
            }
    
            ObjectResult objectResult = new ObjectResult(new { code = 500, message = message });
            context.Result = objectResult;  //context.Result的值会被输入给客户端
            context.ExceptionHandled = true;    //如果赋值为True,则其他的ExceptionFilter不会再执行
            return Task.CompletedTask;
        }
    }
    
  5. 全局注册

    builder.Services.Configure<MvcOptions>(opt =>
    {
        opt.Filters.Add<MyExceptionFilter>();
    });
    
  6. 调用方法Test1后,会出现以下界面:

    ASP.Net Core的Filter_第2张图片

三、Action filter

  1. 实现IAsyncActionFilter接口

  2. 多个Action Filter的链式执行,执行顺序如下:
    ASP.Net Core的Filter_第3张图片

  3. 在TestController中插入以下代码:

    [HttpGet]
    public string Test1()
    {
        Console.WriteLine("开始执行 Test1");
        string s = System.IO.File.ReadAllText("D:1.txt");
        return s;
    }
    
    [HttpGet]
    public DateTime GetDateTime()
    {
        Console.WriteLine("开始执行 GetDateTime");
        return DateTime.Now;
    }
    
  4. 新建一个实现了IAsyncActionFilter接口的类MyActionFilter

    public class MyActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            Console.WriteLine("MyActionFilter 开始执行..."); //在Action之前执行
            ActionExecutedContext result = await next(); 
            
    		//在Action之后执行
            if(result.Exception == null)
            {
                Console.WriteLine("MyActionFilter 执行成功了!");
            }
            else
            {
                Console.WriteLine("MyActionFilter 发生异常了!");
            }
        }
    }
    
  5. 分别调用两个方法可以看到控制台中显示以下内容:
    -

四、实现一个自动启用事务的Action Filter

  1. 创建一个类NotTransactionAttribute ,继承自Attribute,且只能标注到方法上

    [AttributeUsage(AttributeTargets.Method)]
    public class NotTransactionAttribute : Attribute
    {
    }
    
  2. 创建一个类TransactionScopeFilter,实现了IAsyncActionFilter接口

    public class TransactionScopeFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //context.ActionDescriptor  当前被执行的Action方法的描述信息
            ControllerActionDescriptor? controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
    
            bool isTx = false; //是否进行事务控制
            if (controllerActionDescriptor != null)
            {
                //查找当前Action方法的Attribute,是否标记了NotTransactionAttribute
                //如果标记了NotTransactionAttribute,则返回True,就不进行事务控制
                bool hasNotTransactionAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(NotTransactionAttribute), false).Any();
                isTx = !hasNotTransactionAttribute;
            }
    
            if (isTx)
            {
                using (TransactionScope ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
                {
                    var r = await next();
                    if (r.Exception == null)
                    {
                        ts.Complete();
                    }
                }
            }
            else
            {
                await next();
            }
        }
    }
    

你可能感兴趣的:(.net,Core,服务器,c#,java)