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

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

前言:什么是 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 的命名空间
  1. ActionFilterAttribute 如果需要在构造方法中注入某些依赖,比如注入 ILogger,有几个使用方法:
  • TypeFilter,无需在IOC中注册,有自实现,本文例子即是使用这种方式
  • ServiceFilter,需要在 Program.cs 中针对该过滤器注册服务才能使用
  • 自定义 Custo
  • mIOCFilterFactoryAttribute 实现,依然需要对过滤器进行服务注册
  • 方法2和3比较复杂,以后有时间再针对这两种方式写一些例子
  1. 没有注入其他依赖的 ActionFilterAttribute 如一般 Attribute 使用即可,比如本文的第 3 个 ActionFilterAttribute
  • [Test3ActionFilter(“Jacky”)]
相关文章
|
8天前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
29 5
|
18天前
|
开发框架 前端开发 JavaScript
ASP.NET Web Pages - 教程
ASP.NET Web Pages 是一种用于创建动态网页的开发模式,采用HTML、CSS、JavaScript 和服务器脚本。本教程聚焦于Web Pages,介绍如何使用Razor语法结合服务器端代码与前端技术,以及利用WebMatrix工具进行开发。适合初学者入门ASP.NET。
|
2月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
21天前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
26天前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
38 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
16天前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
24 3
|
18天前
|
开发框架 .NET PHP
ASP.NET Web Pages - 添加 Razor 代码
ASP.NET Web Pages 使用 Razor 标记添加服务器端代码,支持 C# 和 Visual Basic。Razor 语法简洁易学,类似于 ASP 和 PHP。例如,在网页中加入 `@DateTime.Now` 可以实时显示当前时间。
|
2月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
106 9
|
2月前
|
存储 开发框架 .NET
.NET 8 实现无实体库表 API 部署服务
【10月更文挑战第12天】在.NET 8中,可通过以下步骤实现无实体库表的API部署:首先安装.NET 8 SDK及开发工具,并选用轻量级Web API框架如ASP.NET Core;接着创建新项目并设计API,利用内存数据结构模拟数据存储;最后配置项目设置并进行测试与部署。此方法适用于小型项目或临时解决方案,但对于大规模应用仍需考虑持久化存储以确保数据可靠性与可扩展性。
|
2月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架