如何在 ASP.NET Core Web API 方法执行前后 “偷偷“ 作一些 “坏“ 事?初识 ActionFilterAttribute

image

前言:什么是 ActionFilterAttribute?

ActionFilterAttribute 是一种作用于控制器 Action 方法的特性(Attribute),通过它,你可以在操作执行前后、异常处理时等不同的阶段插入自定义逻辑。

比如在执行操作方法之前修改请求参数、记录日志、进行权限验证等操作,在执行操作方法之后发送邮件、同步数据等等。

本文主要通过一些例子来说明什么是 ActionFilterAttribute 及如何应用。

Step By Step 步骤:

  1. 创建一个 asp.net core webapi 的项目

  2. 直接继承 ActionFilterAttribute 抽象类创建自定义的 Test1ActionFilterAttribute 类并注入 ILogger

    using Microsoft.AspNetCore.Mvc.Filters;
    namespace AttributeSample
    {
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class Test1ActionFilterAttribute: ActionFilterAttribute
    {
    private ILogger<Test1ActionFilterAttribute> _logger;
    // 在构造方法里注入 ILogger
    public Test1ActionFilterAttribute(ILogger<Test1ActionFilterAttribute> logger)
    {
    _logger = logger;
    }
    /// <summary>
    /// 在控制器执行之前调用
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuting(ActionExecutingContext context)
    {
    _logger.LogInformation("在控制器执行之前调用...");
    base.OnActionExecuting(context);
    }
    /// <summary>
    /// 在控制器执行之后调用
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuted(ActionExecutedContext context)
    {
    _logger.LogInformation("在控制器执行之后调用...");
    base.OnActionExecuted(context);
    }
    }
    }
  3. 通过实现 IActionFilter 接口创建自定义的 Test2ActionFilterAttribute 类并注入 ILogger(推荐方式)

    using Microsoft.AspNetCore.Mvc.Filters;
    namespace AttributeSample
    {
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class Test2ActionFilterAttribute: Attribute, IActionFilter
    {
    private ILogger<Test2ActionFilterAttribute> _logger;
    // 在构造方法里注入 ILogger
    public Test2ActionFilterAttribute(ILogger<Test2ActionFilterAttribute> logger)
    {
    _logger = logger;
    }
    /// <summary>
    /// 在控制器执行之前调用
    /// </summary>
    /// <param name="context"></param>
    public void OnActionExecuting(ActionExecutingContext context)
    {
    _logger.LogInformation("在控制器执行之前调用...");
    }
    /// <summary>
    /// 在控制器执行之后调用
    /// </summary>
    /// <param name="context"></param>
    public void OnActionExecuted(ActionExecutedContext context)
    {
    _logger.LogInformation("在控制器执行之后调用...");
    }
    }
    }
  4. 直接继承 ActionFilterAttribute 抽象类创建自定义的 Test3ActionFilterAttribute 类,不注入其他依赖

    using Microsoft.AspNetCore.Mvc.Filters;
    namespace AttributeSample
    {
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class Test3ActionFilterAttribute: Attribute, IActionFilter
    {
    private string _myName;
    public Test3ActionFilterAttribute(string myName)
    {
    _myName = myName;
    }
    /// <summary>
    /// 在控制器执行之前调用
    /// </summary>
    /// <param name="context"></param>
    public void OnActionExecuting(ActionExecutingContext context)
    {
    _myName += " before";
    }
    /// <summary>
    /// 在控制器执行之后调用
    /// </summary>
    /// <param name="context"></param>
    public void OnActionExecuted(ActionExecutedContext context)
    {
    _myName += " after";
    }
    }
    }
  5. 在控制器中应用自定义的 ActionFilterAttribute

    using Microsoft.AspNetCore.Mvc;
    using AttributeSample;
    using System.Reflection;
    namespace AttributeSample.Controllers
    {
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
    private static readonly string[] Summaries = new[]
    {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
    private readonly ILogger<WeatherForecastController> _logger;
    /// <summary>
    ///
    /// </summary>
    /// <param name="logger"></param>
    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
    _logger = logger;
    }
    [HttpGet(Name = "GetWeatherForecast")]
    [TypeFilter(typeof(Test1ActionFilterAttribute))]
    [TypeFilter(typeof(Test2ActionFilterAttribute))]
    [Test3ActionFilter("Jacky")]
    public IEnumerable<WeatherForecast> Get()
    {
    var list = Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
    Date = DateTime.Now.AddDays(index),
    TemperatureC = Random.Shared.Next(-20, 55),
    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
    _logger.LogInformation("执行方法...");
    return list;
    }
    }
    }
  6. Swaager 测试,可以看到其执行顺序如下:

    AttributeSample.Test1ActionFilterAttribute: Information: 在控制器执行之前调用...
    AttributeSample.Test2ActionFilterAttribute: Information: 在控制器执行之前调用...
    AttributeSample.Test3ActionFilterAttribute...
    AttributeSample.Controllers.WeatherForecastController: Information: 执行方法...
    AttributeSample.Test3ActionFilterAttribute...
    AttributeSample.Test2ActionFilterAttribute: Information: 在控制器执行之后调用...
    AttributeSample.Test1ActionFilterAttribute: Information: 在控制器执行之后调用...

总结:

  1. Asp.net core webapi 使用 ActionFilterAttribute,引用的是 Microsoft.AspNetCore.Mvc.Filters 而不是 System.Web.Http.Filters
    • System.Web.Http.Filters 是属于 .Net FrameWork 的命名空间
  2. ActionFilterAttribute 如果需要在构造方法中注入某些依赖,比如注入 ILogger,有几个使用方法:
    • TypeFilter,无需在IOC中注册,有自实现,本文例子即是使用这种方式
    • ServiceFilter,需要在 Program.cs 中针对该过滤器注册服务才能使用
    • 自定义 CustomIOCFilterFactoryAttribute 实现,依然需要对过滤器进行服务注册
    • 方法2和3比较复杂,以后有时间再针对这两种方式写一些例子
  3. 没有注入其他依赖的 ActionFilterAttribute 如一般 Attribute 使用即可,比如本文的第 3 个 ActionFilterAttribute
    • [Test3ActionFilter("Jacky")]

我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得!欢迎关注老杨的公众号(名称:代码掌控者),和你共同探索代码世界的奥秘!

posted @   代码掌控者  阅读(163)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示