发布于2026-07-20 阅读(0)
扫一扫,手机访问

ASP.NET Core的过滤器,很多人觉得它是个黑盒——写上去就能用,但实际远没那么简单。它的执行顺序、作用域,还有依赖注入的生命周期,这三个点但凡有一个没搞明白,过滤器就可能不触发、注入失败,或者行为完全不对。所以,想用好过滤器,先得把这几个关键点理清楚。
直接实现 IActionFilter 接口,灵活性是最高的,但得自己手动把它注册到DI容器里,比如 services.AddScoped。这一步忘了,那 OnActionExecuting 方法压根不会被执行。相比之下,继承 ActionFilterAttribute 是更常见的做法——它自带属性语法,比如 [MyFilter] 就能直接用,而且在构造函数里注入依赖也是默认支持的。但要注意,这个类必须是 public 的,而且得有一个无参数构造函数,否则运行时就会报 InvalidOperationException: No constructor for type xxx 这样的错。
ActionFilterAttribute,再加上 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] 来控制它到底能用在方法上还是类上。options.Filters.Add() 。但这时候必须得实现接口,而且得把服务注册好。HttpContext 或 IConfiguration 吗?构造函数注入可以,但有个坑:全局注册的过滤器生命周期是 singleton,而 HttpContext 是 scoped 的,直接注入会报 Cannot resolve scoped service from root provider。正确做法是用 context.HttpContext.RequestServices.GetService() 按需解析。不少人以为 options.Filters.Add 和 options.Filters.Add 的调用顺序就是执行顺序,其实不是这么回事。默认情况下,通过 Add 注册的过滤器,Order 值都是 0——是的,你没看错,全是 0。Order 相同时,后添加的反而先执行。所以,如果你想让日志过滤器在外层、认证在内层,就得显式指定 Order 值:
options.Filters.Add(10); // 先执行 options.Filters.Add (20); // 后执行
需要特别注意的是,这个 Order 值只在同一类过滤器中生效。比如两个 IActionFilter 之间可以比较,但跨类型就不行——IAuthorizationFilter 永远比 IActionFilter 先执行,这是由框架设计决定的。
Order 默认是 -1,比全局注册的同类型过滤器优先级更高。Order,避免靠“试出来”的顺序来维护。Order = int.MinValue 和 int.MaxValue 可以作为安全边界,但别用 0 当“默认值”来凑数,那样容易乱。IExceptionFilter 只捕获操作方法内部抛出的异常。模型绑定失败、中间件异常、授权失败(比如 UnauthorizedResult)这些情况,它都不会触发。典型的失效现象是:你加上了 [CustomExceptionFilter],但参数绑定出错时,比如字符串转 int 失败了,页面还是返回 400,而过滤器的 OnException 方法根本没进去。
ModelStateInvalidFilter,它继承自 IActionFilter,在方法里检查 context.ModelState.IsValid 就行。IAuthorizationFilter,在 OnAuthorization 里判断 context.Result is UnauthorizedResult。UseExceptionHandler 中间件,而不是过滤器。context.ExceptionHandled = true 必须显式设置,否则异常会继续向上冒泡,可能被外层中间件再次处理,导致行为异常。全局注册的过滤器默认是 singleton 生命周期,但很多业务服务,比如 IDbContextFactory、ILogger,都是 scoped 的。直接通过构造函数注入,启动时就会报错:Cannot consume scoped service 'xxx' from singleton 'yyy'。
Scoped。但要注意,全局过滤器设为 scoped 后,每次请求都会新建实例,性能开销会稍微增加。context.HttpContext.RequestServices.GetService() 来获取服务。这是最稳妥的做法,特别适合日志、配置、缓存这类轻量级依赖。OnActionExecuting 里 new 一个 DbContext,它不会自动加入当前请求的变更跟踪,Sa veChanges 可能会静默失败,查都查不到。最容易被忽略的一点是:过滤器的执行时机与 MVC 管道阶段是强绑定的,并不是“代码写了就运行”。比如资源过滤器的 OnResourceExecuting 在模型绑定之前执行,这时候 context.ActionArguments 还是空的;而动作过滤器的 OnActionExecuting 执行时,才能看到绑定后的参数。如果看错了阶段,就很容易对着空值做逻辑判断,结果自然不对。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8