重点:ASP.NET Core 里没有直接叫
FilterAttribute的抽象基类 ,是一类过滤器特性 的统称:ActionFilterAttribute/ExceptionFilterAttribute/ResultFilterAttribute;它们继承自Attribute+ 实现对应过滤器接口,用来标记在 Controller / Action 上,在MVC管道中横切执行逻辑(日志、权限、参数校验、异常、响应包装)。
一、5大类过滤器(管道顺序)
- AuthorizationFilter 授权过滤器(最先执行)
- 接口:
IAuthorizationFilter / IAsyncAuthorizationFilter - 作用:登录、权限校验;可以短路管道,直接返回401/403
- 没有内置
AuthorizationFilterAttribute,一般自定义特性或用[Authorize]
2.ResourceFilter 资源过滤器(授权之后、模型绑定之前)
-
- 接口:
IResourceFilter / IAsyncResourceFilter - 场景:缓存、限流、提前短路;比ActionFilter更早
- 接口:
3.ActionFilter 动作过滤器(最常用,Action前后)
-
- 基类:
ActionFilterAttribute(同步) - 4个方法:
-
OnActionExecuting:Action执行之前OnActionExecuted:Action执行之后OnActionExecutionAsync:异步版本(优先用异步)
- 可修改Action参数、修改返回结果、记录耗时、入参日志
- 基类:
4.ResultFilter 结果过滤器(Action执行完、渲染Result前后)
-
- 基类:
ResultFilterAttribute OnResultExecuting:结果渲染前(序列化、返回视图前)OnResultExecuted:结果渲染完成后- 场景:统一包装返回体、添加响应头、修改序列化结果
- 基类:
5.ExceptionFilter 异常过滤器(发生未捕获异常时触发)
-
- 基类:
ExceptionFilterAttribute OnException/OnExceptionAsync- 只在抛出异常时跑;全局统一异常处理、返回友好错误JSON
- 基类:
补充:Razor Page 用
IPageFilter,ActionFilter 不支持Razor Page Handler
二、执行范围 & 优先级(Scope)
作用域从小到大:Action方法 → Controller控制器 → Global全局 执行顺序(before):全局 → 控制器 → 方法 执行顺序(after):方法 → 控制器 → 全局(栈式,先进后出)
同级别多个过滤器:用 Order 属性控制,数字越小越先执行
csharp
[MyFilter(Order = 1)]
三、短路(Short-circuit)
在Filter里直接给 context.Result 赋值,不再往下执行后续管道:
ini
// 授权过滤器里直接拦截
context.Result = new UnauthorizedResult();
异步过滤器:不调用 await next() 就是短路
四、依赖注入问题(非常高频坑)
普通 XXXFilterAttribute 是特性,由new直接实例化,不能直接构造注入DI服务(ILogger、IRepository) 两种解决方案:
- ServiceFilter
- 过滤器类注册到DI容器
services.AddScoped<MyFilter>() - 使用:
[ServiceFilter(typeof(MyFilter))]
2.TypeFilter(推荐,不用注册)
-
[TypeFilter(typeof(MyFilter))],框架自动用ObjectFactory解析DI依赖- 支持传参数:
[TypeFilter(typeof(MyFilter), Arguments = new object[] { "abc" })]
对比:普通Attribute适合无依赖、常量参数;有依赖优先 TypeFilter
五、最简示例:ActionFilterAttribute
csharp
public class LogFilterAttribute : ActionFilterAttribute
{
private readonly Stopwatch _watch;
public override void OnActionExecuting(ActionExecutingContext context)
{
_watch = Stopwatch.StartNew();
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
_watch.Stop();
Console.WriteLine($"接口耗时:{_watch.ElapsedMilliseconds}ms");
base.OnActionExecuted(context);
}
}
// 使用
[LogFilter]
public IActionResult Test()
{
return Ok();
}
六、全局注册(Program.cs)
ini
builder.Services.AddControllers(mvc =>
{
mvc.Filters.Add<LogFilterAttribute>(); // 全局
});
七、过滤器 vs 中间件(Middleware)
- 中间件:在MVC管道外面,整个请求链路(静态资源、api都走),拿到HttpContext,粒度粗
- Filter:MVC内部,只对Controller/Action生效,可以拿到Controller上下文、Action参数、ModelState,粒度细;适合业务横切(权限、返回包装、Action日志)
八、异步写法模板(推荐,项目优先异步)
arduino
public class AsyncFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// before
Console.WriteLine("执行前");
var resultCtx = await next(); // 执行后续过滤器+Action
// after
Console.WriteLine("执行后");
}
}