ASP.NET Core Filters详解:原理、执行顺序与DI使用全解析

ASP.NET Core Filters详解:原理、执行顺序与DI使用全解析
L X Y概述
关于过滤器,我不知道大家了解多少,不过如果了解中间件的话,那么理解这个过滤器也是非常简单的。
过滤器和中间件有很多的相似之处,构成上:前逻辑、后逻辑、next;还有过滤器管道、中间件管道。
既然与中间件如此相似但又不是中间件,那么肯定是有区别的:
| 机制 | 层级 | 拦截范围 | 典型用途 |
|---|---|---|---|
| Middleware | HTTP 管道 | 所有请求,包括静态文件 | CORS、限流、认证、全局日志、异常处理 |
| Filter | MVC 内部 | 仅 Controller / Action | 权限校验(Authorization)、输入参数验证、结果包装、Action 日志、AOP 风格拦截 |
注:Middleware 拦截的是整个 HTTP 请求,而 Filter 只针对 MVC 的 Controller/Action。
过滤器类型
ASP.NET Core 提供 5 种主要过滤器类型:
| 类型 | 接口 | 执行阶段 | 典型应用 |
|---|---|---|---|
| 授权过滤器 | IAuthorizationFilter / IAsyncAuthorizationFilter | 动作前 | 权限验证、身份校验 |
| 资源过滤器 | IResourceFilter / IAsyncResourceFilter | 动作前后 | 缓存、资源预处理 |
| 动作过滤器 | IActionFilter / IAsyncActionFilter | 动作前后 | 日志、模型验证 |
| 异常过滤器 | IExceptionFilter / IAsyncExceptionFilter | 异常发生时 | 捕获异常并处理返回结果 |
| 结果过滤器 | IResultFilter / IAsyncResultFilter | 动作后 | 修改或包装返回结果 |
过滤器在Http管道的位置
那么过滤器在请求管道中的位置如图:
既然刚才看到了,前逻辑、后逻辑、next这三个连在一起出现,那么我相信大多数人第一眼想到的应该是洋葱模型吧,没错,过滤器也有它的洋葱模型
当管道的某个特定阶段有多个筛选器时,作用域可确定筛选器执行的默认顺序。
全局筛选器包围类筛选器,而类筛选器又包围方法筛选器。(类型优先级固定(授权 → 资源 → 动作 → 结果)同类型内部按注册顺序执行)
在筛选器嵌套模式下,筛选器的 after 代码会按照与 before 代码相反的顺序运行。 筛选器序列:
- 全局筛选器的 before 代码。
- 控制器筛选器的 before 代码。
- 操作方法筛选器的 before 代码。
- 操作方法筛选器的 after 代码。
- 控制器筛选器的 after 代码。
- 控制器筛选器的 before 代码。
- 全局筛选器的 after 代码。
注:异常过滤器(Exception)不参与正常顺序,它只在抛出未捕获异常时触发。
而它的管道画出来大概就是这样:
Filter实现
这里我先给一个关于 过滤器 注册的表格,现在看不懂没有关系
| 依赖DI | 不依赖DI | 说明 | |
|---|---|---|---|
| 全局 | builder.Services.AddScoped builder.Services.AddControllers(options =>{options.Filters.AddService |
options.Filters.Add |
全局过滤器会作用于所有 Controller 和 Action;有参构造必须用 AddService |
| 非全局 | builder.Services.AddScoped |
在过滤器定义类的实现接口位置添加 Attribute 注意放在第一位 | Attribute 用于定义特性类,方便控制器或方法添加该特性 |
注:Attribute 用于定义特性类,让控制器或者相关的方法可以添加该特性
注:依赖 DI 的过滤器需要注册到容器(AddScoped / AddTransient / AddSingleton 均可,具体取决于使用场景)
注:有参全局过滤器必须使用 AddService
除了在AddControllers()中注册全局过滤器,也可以在其他地方注册:
| 方法 | 支持的功能 | 常用场景 | 过滤器注册效果 |
|---|---|---|---|
AddControllers() |
仅支持 API Controller([ApiController]) | Web API | 可以注册全局过滤器,但只影响 API 控制器方法 |
AddControllersWithViews() |
API + MVC View 支持 | 传统 MVC | 注册全局过滤器,可作用于 Controller + ViewAction |
AddMvc() |
API + MVC + RazorPages 全支持 | 综合应用 | 注册全局过滤器,作用最广 |
全局-依赖DI
GlobalLogFilter:
1 | using Microsoft.AspNetCore.Mvc.Filters; |
program:
1 | //全局-依赖DI |
操作方法:
1 | [] |
运行截图:
全局-不依赖DI
GlobalFilter:
1 | using Microsoft.AspNetCore.Mvc.Filters; |
program:
1 | builder.Services.AddControllers(options => |
全局过滤器作用于所有 Controller/Action;非全局只作用于指定 Controller 或方法。
控制器不变,看一下两份代码有什么区别?
首先第一个过滤器的不同, GlobalLogFilter 它的过滤器是构造函数含参ILogger类型,它有了 DI容器的依赖;
第二个不同,program 中
前者:builder.Services.AddScoped
除此之外的不同
| 方法 | DI 支持 | 构造函数限制 | 场景 |
|---|---|---|---|
options.Filters.Add<T>() |
❌ 不走 DI | 必须无参构造函数 | 全局非 DI 过滤器、Attribute 过滤器 |
options.Filters.AddService<T>() |
✔ 走 DI | 可以有依赖参数 | 全局 DI 过滤器、复杂日志、数据库操作等 |
注:AddService 注册的全局过滤器依赖 DI 生命周期(Scoped/Singleton/Transient)和服务容器。
非全局-依赖DI
NonGlobalLogFilter:
1 | using Microsoft.AspNetCore.Mvc.Filters; |
program:
1 | //非全局-依赖DI |
非全局-不依赖DI
NonGlobalFilter:
1 | using Microsoft.AspNetCore.Mvc.Filters; |
Attribute 这个接口了,是用来定义特性类的,且需要放在定义类的接口的第一个位置
注:有参构造的过滤器一定要走 DI,否则无法注入服务。
program:
1 | //没有需要添加的 |
这个两个非全局过滤器的使用:
TestController:
1 | using Microsoft.AspNetCore.Http; |
区别是特性标签不同:一个是[ServiceFilter(typeof(NonGlobalLogFilter))] ,另一个是[NonGlobalFilter]
你也可以把它们的位置换过来.
运行截图:
从图里面看,这也确实是一个洋葱模型
总结
ASP.NET Core Filters 是 MVC 内部的“轻量级管道”,类似洋葱模型。
类型优先级固定:授权 → 资源 → 动作 → 结果。
DI 支持与否影响注册方式和构造函数限制。
全局/非全局决定作用范围。
通过合理组合,可以实现日志、权限、缓存、异常处理等功能。








