NETCore入门系列(AOP之ActionFilter)

一、ActionFilter入门

使用场景

一般用于Action的日志记录。

官方介绍

官方链接

实操

1、创建CustomActionFilterAttribute类,需实现Attribute(实现了Attribute才可在控制器中进行标注)和IActionFilter接口。
2、CustomActionFilterAttribute类代码如下:

    /// <summary>
    /// 自定义ActionFilter
    /// </summary>
    
    public class CustomActionFilterAttribute :Attribute,IActionFilter
    {
        /// <summary>
        /// action执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine("正在执行OnActionExecuted。。。");
        }
        /// <summary>
        /// action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            string controllerName = context.ActionDescriptor.RouteValues["controller"];
            string actionName = context.ActionDescriptor.RouteValues["action"];
            string res = $"Controller:{controllerName},Action:{actionName}\n{context.Result}";
            Console.WriteLine("正在执行OnActionExecuting。。。");
        }
    }

3、打开HomeController,在构造函数和Index函数中填写以下代码:

private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
            Console.WriteLine("正在执行HomeController构造函数。。。");
        }

        [CustomActionFilter]//标记自定义ActionFilter
        public IActionResult Index()
        {
            Console.WriteLine("正在执行HomeController的Index函数。。。");
            return View();
        }

4、运行项目,可看到控制台进行如下输出,说明当前的执行顺序为:
“构造函数”->“OnActionExecuting”->“Index函数”->“OnActionExecuted”。
在这里插入图片描述

二、Filter传参

当想要在Filter使用日志中间件时,会提示需要传递形参"logger"(原因是自定义的Filter没法直接支持依赖注入),此时提供一个无参构造函数可以通过编译,但是运行时可以发现_logger参数就为空(因为都没走有参构造函数)。那么该如何解决呢?微软给我们提供了"TypeFilter"和"ServiceFilter"来支持依赖注入。
在这里插入图片描述在这里插入图片描述

TypeFilter

此时将控制器中的代码做如下更改,可看到不会报错,且运行项目后可看到正确的输出(注:将 Console.WriteLine()更改为_logger.LogInformation(),具体请看文末的源码链接)。

 //[CustomActionFilter] //是一个特性,故可以去掉后面的Attribute,无参
        [TypeFilter(typeof(CustomActionFilterAttribute))]//此时不是特性,故需要完整类名
        public IActionResult Index()
        {
            Console.WriteLine("正在执行HomeController的Index函数。。。");
            return View();
        }

在这里插入图片描述

ServiceFilter

1、此时将控制器中Index函数的特性更改为[ServiceFilter(typeof(CustomActionFilterAttribute))],并运行项目,会出现如下的错误:

InvalidOperationException: No service for type 'FilterWebApp.Utils.Filters.CustomActionFilterAttribute' has been registered.
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

2、上述错误告诉我们需要注册服务,此时我们在startup.cs中对该类进行注册后,重新运行,就不会报错了。

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();

            services.AddSingleton<CustomActionFilterAttribute>();//单例注册服务
        }

3、在这里看一下官方解析(官方的建议是使用服务时才使用ServiceFilter):
在这里插入图片描述

ServiceFilter主要用于FilterCollection.AddService调用。与Microsoft.AspNetCore.Mvc.TypeFilterAttribute类似,两者都使用构造函数注入。如果筛选器本身不是服务,请改用Microsoft.AspNetCore.Mvc.TypeFilterAttribute。

在这里插入图片描述

三、Filter作用域

1、添加CustomControllerActionFilterAttributeCustomGlobalActionFilterAttribute,一个用于标注控制器,一个用于全局注册,与之前标注在函数上的进行比较,打印输出他们的执行顺序,并进行分析。
2、三个Filter的代码如下:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FilterWebApp.Utils.Filters
{
    /// <summary>
    /// 自定义ActionFilter
    /// </summary>
    
    public class CustomActionFilterAttribute :Attribute,IActionFilter
    {
        //private readonly ILogger<CustomActionFilterAttribute> _logger;

        //public CustomActionFilterAttribute(ILogger<CustomActionFilterAttribute> logger)
        //{
        //    _logger = logger;
        //    _logger.LogInformation("正在执行CustomActionFilterAttribute构造函数");
        //}

        public CustomActionFilterAttribute()
        {
            Console.WriteLine("正在执行Action Filter 的构造函数。。。");
        }


        /// <summary>
        /// action执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine("正在执行Action Filter 的OnActionExecuted。。。");
            //_logger.LogInformation("Log:正在执行OnActionExecuted。。。");
        }
        /// <summary>
        /// action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            string controllerName = context.ActionDescriptor.RouteValues["controller"];
            string actionName = context.ActionDescriptor.RouteValues["action"];
            string res = $"Controller:{controllerName},Action:{actionName}\n{context.Result}";
            Console.WriteLine("正在执行Action Filter 的OnActionExecuting。。。");
           // _logger.LogInformation("Log:正在执行OnActionExecuting。。。");
        }
    }



    /// <summary>
    /// 自定义控制器ActionFilter
    /// </summary>

    public class CustomControllerActionFilterAttribute : Attribute, IActionFilter
    {
        

        public CustomControllerActionFilterAttribute()
        {          
            Console.WriteLine("正在执行Controller Filter的构造函数");
        }


        /// <summary>
        /// action执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
             Console.WriteLine("正在执行Controller Filter的OnActionExecuted。。。");
            
        }
        /// <summary>
        /// action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
             Console.WriteLine("正在执行Controller Filter的OnActionExecuting。。。");
        }
    }


    /// <summary>
    /// 全局ActionFilter
    /// </summary>

    public class CustomGlobalActionFilterAttribute : Attribute, IActionFilter
    {


        public CustomGlobalActionFilterAttribute()
        {
            Console.WriteLine("正在执行Global Filter 的构造函数。。");
        }


        /// <summary>
        /// action执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine("正在执行Global Filter 的OnActionExecuted。。。");

        }
        /// <summary>
        /// action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine("正在执行Global Filter 的OnActionExecuting。。。");
        }
    }

}

3、执行顺序为"Global Executing"->“Controller Executing”->“Action Executing”->“Action Executed”->“Controller Executed”->“Global Executed”,如下图:
在这里插入图片描述官方提供的管道中间件执行流程图:
在这里插入图片描述
项目输出:
在这里插入图片描述
注:如果想更改Filter的执行顺序,可通过实现IOrderedFilter接口,也可以直接继承官方的ActionFilterAttribute,这个是官方对IActionFilterIOderedFilter等接口的实现,如下:
在这里插入图片描述

四、源码

https://gitee.com/wusuoweixgy/NET5Code/tree/master/FilterWebApp

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值