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

徐锦洪  金牌会员 | 2024-9-19 21:31:03 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 620|帖子 620|积分 1860


前言:什么是 ActionFilterAttribute?

ActionFilterAttribute 是一种作用于控制器 Action 方法的特性(Attribute),通过它,你可以在操作执行前后、异常处理时等不同的阶段插入自定义逻辑。
比如在执行操作方法之前修改请求参数、记录日记、进行权限验证等操作,在执行操作方法之后发送邮件、同步数据等等。
本文主要通过一些例子来说明什么是 ActionFilterAttribute 及如何应用。
Step By Step 步骤:


  • 创建一个 asp.net core webapi 的项目
  • 直接继承 ActionFilterAttribute 抽象类创建自定义的 Test1ActionFilterAttribute 类并注入 ILogger
    1. using Microsoft.AspNetCore.Mvc.Filters;
    2. namespace AttributeSample
    3. {
    4.         [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    5.         public class Test1ActionFilterAttribute: ActionFilterAttribute
    6.         {
    7.                 private ILogger<Test1ActionFilterAttribute> _logger;
    8.                
    9.                 // 在构造方法里注入 ILogger
    10.                 public Test1ActionFilterAttribute(ILogger<Test1ActionFilterAttribute> logger)
    11.                 {
    12.                         _logger = logger;
    13.                 }
    14.                
    15.                 /// <summary>
    16.                 /// 在控制器执行之前调用
    17.                 /// </summary>
    18.                 /// <param name="context"></param>
    19.                 public override void OnActionExecuting(ActionExecutingContext context)
    20.                 {
    21.                         _logger.LogInformation("在控制器执行之前调用...");
    22.                         base.OnActionExecuting(context);
    23.                 }
    24.                 /// <summary>
    25.                 /// 在控制器执行之后调用
    26.                 /// </summary>
    27.                 /// <param name="context"></param>
    28.                 public override void OnActionExecuted(ActionExecutedContext context)
    29.                 {
    30.                         _logger.LogInformation("在控制器执行之后调用...");
    31.                         base.OnActionExecuted(context);
    32.                 }
    33.         }
    34. }
    复制代码
  • 通过实现 IActionFilter 接口创建自定义的 Test2ActionFilterAttribute 类并注入 ILogger(推荐方式)
    1. using Microsoft.AspNetCore.Mvc.Filters;
    2. namespace AttributeSample
    3. {
    4.         [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    5.         public class Test2ActionFilterAttribute: Attribute, IActionFilter
    6.         {
    7.                 private ILogger<Test2ActionFilterAttribute> _logger;
    8.                
    9.                 // 在构造方法里注入 ILogger
    10.                 public Test2ActionFilterAttribute(ILogger<Test2ActionFilterAttribute> logger)
    11.                 {
    12.                         _logger = logger;
    13.                 }
    14.                
    15.                 /// <summary>
    16.                 /// 在控制器执行之前调用
    17.                 /// </summary>
    18.                 /// <param name="context"></param>
    19.                 public void OnActionExecuting(ActionExecutingContext context)
    20.                 {
    21.                         _logger.LogInformation("在控制器执行之前调用...");
    22.                 }
    23.                 /// <summary>
    24.                 /// 在控制器执行之后调用
    25.                 /// </summary>
    26.                 /// <param name="context"></param>
    27.                 public void OnActionExecuted(ActionExecutedContext context)
    28.                 {
    29.                         _logger.LogInformation("在控制器执行之后调用...");
    30.                 }
    31.         }
    32. }
    复制代码
  • 直接继承 ActionFilterAttribute 抽象类创建自定义的 Test3ActionFilterAttribute 类,不注入其他依靠
    1. using Microsoft.AspNetCore.Mvc.Filters;
    2. namespace AttributeSample
    3. {
    4.         [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    5.         public class Test3ActionFilterAttribute: Attribute, IActionFilter
    6.         {
    7.                 private string _myName;
    8.                 public Test3ActionFilterAttribute(string myName)
    9.                 {
    10.                         _myName = myName;
    11.                 }
    12.                 /// <summary>
    13.                 /// 在控制器执行之前调用
    14.                 /// </summary>
    15.                 /// <param name="context"></param>
    16.                 public void OnActionExecuting(ActionExecutingContext context)
    17.                 {
    18.                         _myName += " before";
    19.                 }
    20.                 /// <summary>
    21.                 /// 在控制器执行之后调用
    22.                 /// </summary>
    23.                 /// <param name="context"></param>
    24.                 public void OnActionExecuted(ActionExecutedContext context)
    25.                 {
    26.                         _myName += " after";
    27.                 }
    28.         }
    29. }
    复制代码
  • 在控制器中应用自定义的 ActionFilterAttribute
    1. using Microsoft.AspNetCore.Mvc;
    2. using AttributeSample;
    3. using System.Reflection;
    4. namespace AttributeSample.Controllers
    5. {
    6.         [ApiController]
    7.         [Route("[controller]")]
    8.         public class WeatherForecastController : ControllerBase
    9.         {
    10.                 private static readonly string[] Summaries = new[]
    11.                 {
    12.                         "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    13.                 };
    14.                 private readonly ILogger<WeatherForecastController> _logger;
    15.                 /// <summary>
    16.                 ///
    17.                 /// </summary>
    18.                 /// <param name="logger"></param>
    19.                 public WeatherForecastController(ILogger<WeatherForecastController> logger)
    20.                 {
    21.                         _logger = logger;
    22.                 }
    23.                 [HttpGet(Name = "GetWeatherForecast")]
    24.                 [TypeFilter(typeof(Test1ActionFilterAttribute))]
    25.                 [TypeFilter(typeof(Test2ActionFilterAttribute))]
    26.                 [Test3ActionFilter("Jacky")]
    27.                 public IEnumerable<WeatherForecast> Get()
    28.                 {
    29.                         var list = Enumerable.Range(1, 5).Select(index => new WeatherForecast
    30.                         {
    31.                                 Date = DateTime.Now.AddDays(index),
    32.                                 TemperatureC = Random.Shared.Next(-20, 55),
    33.                                 Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    34.                         })
    35.                         .ToArray();
    36.                         _logger.LogInformation("执行方法...");
    37.                         return list;
    38.                 }
    39.         }
    40. }
    复制代码
  • 在 Swaager 测试,可以看到其执行顺序如下:
    1. AttributeSample.Test1ActionFilterAttribute: Information: 在控制器执行之前调用...
    2. AttributeSample.Test2ActionFilterAttribute: Information: 在控制器执行之前调用...
    3. AttributeSample.Test3ActionFilterAttribute...
    4. AttributeSample.Controllers.WeatherForecastController: Information: 执行方法...
    5. AttributeSample.Test3ActionFilterAttribute...
    6. AttributeSample.Test2ActionFilterAttribute: Information: 在控制器执行之后调用...
    7. AttributeSample.Test1ActionFilterAttribute: Information: 在控制器执行之后调用...
    复制代码
总结:


  • Asp.net core webapi 使用 ActionFilterAttribute,引用的是 Microsoft.AspNetCore.Mvc.Filters 而不是 System.Web.Http.Filters

    • System.Web.Http.Filters 是属于 .Net FrameWork 的命名空间

  • ActionFilterAttribute 如果需要在构造方法中注入某些依靠,比如注入 ILogger,有几个使用方法:

    • TypeFilter,无需在IOC中注册,有自实现,本文例子便是使用这种方式
    • ServiceFilter,需要在 Program.cs 中针对该过滤器注册服务才能使用
    • 自定义 CustomIOCFilterFactoryAttribute 实现,依然需要对过滤器进行服务注册
    • 方法2和3比力复杂,以后有时间再针对这两种方式写一些例子

  • 没有注入其他依靠的 ActionFilterAttribute 如一般 Attribute 使用即可,比如本文的第 3 个 ActionFilterAttribute

    • [Test3ActionFilter("Jacky")]

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

徐锦洪

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表