ASP.NET Core过滤器需正确配置执行顺序、DI生命周期和接口实现方式,否则OnActionExecuting不触发或注入失败;特性标记用ActionFilterAttribute(需无参构造),全局注册用IActionFilter(需手动注册);HttpContext等scoped服务须延迟解析;Order值决定同类型执行顺序,默认0,特性默认-1优先级最高;IExceptionFilter不捕模型绑定异常,异步操作必须用IAsyncActionFilter。

直接说结论:ASP.NET Core 的过滤器不是“加个 [MyFilter] 就能跑”,它卡在三个地方——执行顺序没设对、DI 生命周期混用、接口实现方式选错。漏掉任一,OnActionExecuting 就不会进,或者注入失败报 InvalidOperationException: No constructor for type xxx 或 Cannot resolve scoped service from root provider。
怎么选 IActionFilter 还是 ActionFilterAttribute
看你用不用特性标记和是否需要构造函数注入:
- 要写
[MyFilter]标在 Controller 或 Action 上 → 继承ActionFilterAttribute,但类必须是public,且要有无参构造函数(哪怕只是public MyFilter() : base() { });否则运行时报No constructor for type xxx - 想全局注册、不依赖属性标记、又需要灵活控制生命周期 → 直接实现
IActionFilter接口,但必须手动注册进 DI,比如services.AddScoped<myfilter>()</myfilter>,否则方法根本不会被调用 - 两者都实现了同步/异步接口?运行时只认异步的(
IAsyncActionFilter),同步方法(IActionFilter)会被跳过
全局注册时 HttpContext 注入失败怎么办
全局注册的过滤器默认是 singleton 生命周期,而 HttpContext 是 scoped 服务,直接构造函数注入会崩在启动时:Cannot resolve scoped service from root provider。
正确做法是延迟解析:
- 不要在构造函数里注入
IHttpContextAccessor或HttpContext - 改在
OnActionExecuting里用context.HttpContext.RequestServices.GetService<imyservice>()</imyservice>拿服务 - 如果真要用
IHttpContextAccessor,得先注册为 singleton:services.AddSingleton<ihttpcontextaccessor httpcontextaccessor>()</ihttpcontextaccessor>,但注意它返回的HttpContext可能为 null(比如后台线程中)
Order 值为什么设了也不生效
Order 不是“谁先 Add 谁先跑”,而是同类型过滤器之间按数值升序执行(小的先执行),默认值全是 0 —— 所以后 Add 的反而先触发。
- 想让日志过滤器包在最外层、权限校验在内层?得显式设:
options.Filters.Add<logfilter>(10)</logfilter>和options.Filters.Add<authfilter>(20)</authfilter> - Controller 或 Action 上的特性过滤器默认
Order = -1,比所有全局同类型过滤器都优先,别指望全局设置能盖过它 -
IAuthorizationFilter总是比IActionFilter先跑,跨类型不比Order;混用时建议所有过滤器都显式设Order,避免靠试
异常过滤器捕不到模型绑定失败怎么办
IExceptionFilter 只捕操作方法或结果执行中抛出的异常,不捕模型绑定、路由、中间件阶段的异常——那些早于过滤器管道就挂了。
- 模型绑定失败(如参数类型不匹配)触发的是
ModelState.IsValid == false,不是异常,得在IActionFilter.OnActionExecuting里检查 - 想统一处理绑定错误?用
ModelStateInvalidFilter(继承IActionFilter)或自定义ProblemDetails响应 - 真正未捕获的异常(比如数据库连接失败)才进
IExceptionFilter.OnException,记得调context.ExceptionHandled = true防止被上层再处理
最常被忽略的一点:过滤器里的逻辑如果涉及异步 IO(比如查 DB、发 HTTP 请求),必须用 IAsyncActionFilter + await,硬塞同步方法里调 .GetAwaiter().GetResult() 会导致线程死锁,尤其在 IIS 或高并发场景下静默失败。


















