ASP.NET Core中如何让全局过滤器OnActionExecuting优先于控制器执行?
如何让全局过滤器的OnActionExecuting先于控制器同名方法执行(ASP.NET Core 2.0)
我之前在ASP.NET Core 2.0项目里也遇到过一模一样的问题——默认情况下控制器重写的OnActionExecuting会抢在全局过滤器的同名方法前面执行,完全打乱了前置准备的逻辑。不过别担心,我们可以通过调整过滤器执行顺序轻松解决这个问题。
核心原理
ASP.NET Core中过滤器的执行顺序由Order属性控制:数值越小,执行优先级越高。控制器中重写的OnActionExecuting方法本质上属于控制器级别的ActionFilter,它的默认Order值是0。所以只要我们给全局过滤器设置一个比0更小的Order值,就能让它先执行。
方法一:让全局过滤器实现IOrderedFilter接口
直接在过滤器类里实现IOrderedFilter接口,并设置Order为小于0的值(比如-1):
public class GlobalPrepFilter : IActionFilter, IOrderedFilter { // 设置优先级高于控制器默认的0 public int Order { get; } = -1; public void OnActionExecuting(ActionExecutingContext context) { // 这里的逻辑会优先执行,完成前置准备 // 可以通过HttpContext.Items传递数据给控制器 context.HttpContext.Items["PrepData"] = "全局过滤器准备好的初始化数据"; } public void OnActionExecuted(ActionExecutedContext context) { // 后置逻辑按需实现,不用可以留空 } }
然后在Startup.cs中注册这个全局过滤器:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add<GlobalPrepFilter>(); }); }
方法二:注册时直接指定Order值
如果不想修改过滤器类,也可以在注册全局过滤器时直接传入order参数:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // 直接指定order为-1,优先级高于控制器默认值 options.Filters.Add(new GlobalPrepFilter(), order: -1); }); }
控制器中的使用示例
现在控制器的OnActionExecuting会在全局过滤器之后执行,你可以直接获取全局过滤器传递的数据:
public class HomeController : Controller { public override void OnActionExecuting(ActionExecutingContext context) { // 从HttpContext.Items中读取全局过滤器传递的数据 if (context.HttpContext.Items.TryGetValue("PrepData", out var prepData)) { ViewBag.InitData = prepData.ToString(); } // 一定要调用基类方法,避免破坏控制器默认逻辑 base.OnActionExecuting(context); } }
注意事项
- 不要忘记调用基类的
OnActionExecuting方法,否则可能会跳过控制器基类中的默认初始化逻辑,引发意外问题。 - 如果有多个全局过滤器,它们的执行顺序会按照
Order值从小到大排列;Order值相同的情况下,会按照注册顺序执行。
内容的提问来源于stack exchange,提问作者Juliën
相关产品推荐
相关产品推荐

