.NET Core中的五种过滤器详解
目录
- 过滤器概述
- 1. 授权过滤器(Authorization Filters)
- 2. 资源过滤器(Resource Filters)
- 3. 动作过滤器(Action Filters)
- 4. 异常过滤器(Exception Filters)
- 5. 结果过滤器(Result Filters)
- 6过滤器的使用方式
- 7 测试过滤器执行
- 8 过滤器中注入服务
- 9 .NET Core中间件和过滤器的异同
过滤器概述
在 .NET Core 中,过滤器(Filters)和面向切面编程(AOP)有着紧密的联系,过滤器可以看作是 AOP 在 .NET Core 框架中的一种具体实现方式。
在.NET Core中过滤器是一种特殊的组件,它能够在请求处理管道的特定阶段执行自定义逻辑。借助过滤器,你可以把横切关注点(像日志记录、权限验证、异常处理等)从业务逻辑中分离出来,从而提升代码的可维护性与可复用性。
1. 授权过滤器(Authorization Filters)
作用:用于验证用户是否有权限访问某个资源,在请求进入控制器之前执行。若验证不通过,会阻止请求继续执行。
示例代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class CtsAuthorizationAttribute : Attribute, IAuthorizationFilter
{
// 鉴权
public void OnAuthorization(AuthorizationFilterContext context)
{
// 在进入控制器构造方法前执行,
Console.WriteLine(" Authorization ========= OnAuthorization");
}
}
2. 资源过滤器(Resource Filters)
作用:在授权之后、模型绑定之前执行,主要用于缓存和资源管理。
示例代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
/// <summary>
/// 自定义资源验证过滤器
/// </summary>
public class CtsResourceFilterAttribute : Attribute, IResourceFilter
{
// 资源验证之后
public void OnResourceExecuted(ResourceExecutedContext context)
{
Console.WriteLine("ResourceFilter=============OnResourceExecuted");
}
// 资源验证之前
public void OnResourceExecuting(ResourceExecutingContext context)
{
// 当context的Result 不等于空时, 被短路,不再会像下执行业务逻辑
// 节省资源的开销
// 通常利用该性质 做数据的缓存处理,[直接在进入控制器的方法前就获得了返回数据]
Console.WriteLine("ResourceFilter=============OnResourceExecuting");
}
}
3. 动作过滤器(Action Filters)
作用:在控制器方法执行前后执行,可用于日志记录、参数验证等。
示例代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
/// <summary>
/// 自定义动作验证过滤器
/// </summary>
public class CtsActionFilterAttribute : Attribute, IActionFilter
{
// 进入方法后
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine(" ActionFilter ========= OnActionExecuted");
}
// 进入方法前
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("ActionFilter ========= OnActionExecuting");
}
}
4. 异常过滤器(Exception Filters)
作用:在发生异常时执行,用于统一处理异常,避免异常信息直接暴露给客户端。
示例代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
/// <summary>
/// 自定义异常过滤器
/// </summary>
public class CtsExceptionFilterAttribute : Attribute, IExceptionFilter
{
// 捕获异常处理[该异常只能捕获目标方法前后及过滤器本身抛出的异常[作用范围较小]
// 异常中间件的放置的位置较为前面,能够捕获请求生命周期件发生的所有异常信息[作用范围大]
public void OnException(ExceptionContext context)
{
// 异常处理逻辑
System.Console.WriteLine($"An exception occurred: {context.Exception.Message}");
context.Result = new JsonResult("Error"); // 过滤器可以通过设置 context.Result 属性来实现短路
}
}
5. 结果过滤器(Result Filters)
作用:在动作结果执行前后执行,用于对动作结果进行格式化、加密等处理。
示例代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
/// <summary>
/// 自定义结果过滤器
/// 仅仅当操作过滤器生成操作结果时,才会执行结果过滤器.不会授权过滤器或者资源过滤器或者异常过滤器短路[Result有值]时
/// </summary>
public class CtsResultFilterAttribute : Attribute, IResultFilter
{
/// <summary>
/// 结果赋值后,此时获得目标方法的响应结果数据
/// </summary>
/// <param name="context"></param>
public void OnResultExecuted(ResultExecutedContext context)
{
Console.WriteLine(" ResultFilter ========= OnResultExecuted");
}
/// <summary>
/// 结果赋值前
/// </summary>
/// <param name="context"></param>
public void OnResultExecuting(ResultExecutingContext context)
{
Console.WriteLine(" ResultFilter ========= OnResultExecuting");
}
}
6过滤器的使用方式
全局过滤器:在 Startup.cs(.NET 5 及以下版本)或者 Program.cs(.NET 6 及以上版本)中进行全局注册,会对所有的控制器和动作方法生效。
// .NET 6 及以上版本的 Program.cs
var builder = WebApplication.CreateBuilder(args);
// 注册全局过滤器
builder.Services.AddControllers(options =>
{
// 这里全局注册自定义的方法过滤器
options.Filters.Add(typeof(CtsActionFilterAttribute));
});
var app = builder.Build();
app.MapControllers();
app.Run();
控制器级别过滤器:在控制器类上应用过滤器,会对该控制器中的所有动作方法生效。
[CtsActionFilter]
public class MyController : Controller
{
// 控制器方法
}
动作方法级别过滤器:在具体的动作方法上应用过滤器,仅对该动作方法生效。
public class MyController : Controller
{
[CtsActionFilter]
public IActionResult MyAction()
{
return Ok();
}
}
一般来说,在同级别的过滤器下,过滤器的执行顺序是从全局到控制器再到方法
7 测试过滤器执行
在目标方法上添加上述五种过滤器, 通过 /WeatherForecast 路径去请求Get方法
[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;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
Console.WriteLine("Into WeatherForecastController Constructor Function");
_logger = logger;
}
[CtsResourceFilter]
[CtsAuthorization]
[CtsActionFilter]
[CtsExceptionFilter]
[CtsResultFilter]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
测试结果如下
. 过滤器的执行存在着一定的先后顺序通常是:授权过滤器 -> 资源过滤器(执行前) -> 动作过滤器(执行前) -> 控制器方法 -> 动作过滤器(执行后) -> 结果过滤器(执行前) -> 动作结果执行 -> 结果过滤器(执行后) -> 资源过滤器(执行后)。若在任何阶段发生异常,异常过滤器会被触发。
8 过滤器中注入服务
在 .NET Core 中,在过滤器中注入服务是一种常见的操作,这样可以让过滤器使用其他服务提供的功能,例如数据库访问、日志记录等 。有两种主要的过滤器类型可以注入服务:[TypeFilter] 特性和 [ServiceFilter]特性。 这里以记录ActionFilter中的请求信息为例,在ActionFilter注入日志服务
/// <summary>
/// 自定义动作验证过滤器
/// </summary>
public class CtsActionFilterAttribute : Attribute, IActionFilter
{
ILogger<CtsActionFilterAttribute> _logger;
public CtsActionFilterAttribute(ILogger<CtsActionFilterAttribute> logger)
{
_logger = logger;
}
// 进入方法后
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation("ActionFilter ========= OnActionExecuted");
}
// 进入方法前
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("ActionFilter ========= OnActionExecuting");
}
}
- 使用[TypeFilter]特性添加方法级别的过滤器
[TypeFilter(typeof(CtsActionFilterAttribute))]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
/// 忽略执行逻辑
}
- 使用[ServiceFilter]特性添加方法级别的过滤器
[ServiceFilter(typeof(CtsActionFilterAttribute))]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
/// 忽略执行逻辑
}
同时需要在容器中注入CtsActionFilterAttribute
builder.Services.AddTransient<CtsActionFilterAttribute>();
两者的区别在于是不是需要注入过滤器本身.
这是因为TypeFilterAttribute 会根据类型信息,尝试从容器中解析其依赖项,然后直接创建过滤器实例.
ServiceFilterAttribute直接从依赖注入容器中解析过滤器实例。这要求过滤器必须在依赖注入容器中进行注册。
9 .NET Core中间件和过滤器的异同
- 相同点
(1) 两者都用于对请求和响应进行预处理和后处理,以增强应用程序的功能。帮助开发者将横切关注点(如安全性、日志等)从核心业务逻辑中分离出来,提高代码的可维护性和可复用性。是.NET Core中AOP的不同实现方式
(2) 通常都以链式的方式工作。多个中间件或过滤器可以按照一定的顺序依次执行 - 不同点
(1) 中间件是更底层的组件,与 Web 服务器或应用程序的请求处理管道紧密相关,它直接处理 HTTP 请求和响应,能够在请求到达具体的业务处理逻辑之前进行拦截和处理,作用范围更广;过滤器主要应用于控制器和动作方法级别,可对特定的控制器或动作方法进行精细的控制,实现细粒度的功能增强,
(2) 中间件是对所有请求进行统一处理,难以针对特定的控制器或动作方法进行精细的配置。
过滤器具有较高的灵活性,能够针对不同的控制器和动作方法进行不同的配置。