在ASP.NET Core中,在控制器的OnActionExecuting之前执行全局过滤器

Jul*_*iën 12 c# action-filter .net-core asp.net-core

在ASP.NET Core 2.0应用程序中,我尝试OnActionExecuting 执行Controller的变体之前执行全局过滤器.预期的行为是我可以在全局之前准备一些东西并将结果值传递给控制器​​.然而,当前的行为是执行的顺序被设计颠倒了.

文档告诉我默认的执行顺序:

从Controller基类继承的每个控制器都包含OnActionExecuting和OnActionExecuted方法.这些方法包装为给定操作运行的过滤器:在任何过滤器之前调用OnActionExecuting,并在所有过滤器之后调用OnActionExecuted.

这导致我解释Controller OnActionExecuting在任何过滤器之前执行.说得通.但是文档还声明可以通过实现来覆盖默认顺序IOrderedFilter.

我尝试在过滤器中实现这一点是这样的:

public class FooActionFilter : IActionFilter, IOrderedFilter
{
    // Setting the order to 0, using IOrderedFilter, to attempt executing
    // this filter *before* the BaseController's OnActionExecuting.
    public int Order => 0;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // removed logic for brevity
        var foo = "bar";

        // Pass the extracted value back to the controller
        context.RouteData.Values.Add("foo", foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

此过滤器在启动时注册为:

services.AddMvc(options => options.Filters.Add(new FooActionFilter()));
Run Code Online (Sandbox Code Playgroud)

最后,我的BaseController看起来像下面的示例.这最好地解释了我想要实现的目标:

public class BaseController : Controller
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // The problem: this gets executed *before* the global filter.
        // I actually want the FooActionFilter to prepare this value for me.
        var foo = context.RouteData.Values.GetValueOrDefault("foo").ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

设置Order为0,或甚至像-1这样的非零值似乎对执行顺序没有任何影响.

我的问题:如何让我的全局过滤器在(基本)控制器OnActionExecuting 之前执行OnActionExecuting

Cod*_*ler 8

你快到了。您的小错误是,控制器过滤器执行的默认顺序不是0。该顺序在ControllerActionFilter类中定义为int.MinValue源代码):

public class ControllerActionFilter : IAsyncActionFilter, IOrderedFilter
{
    // Controller-filter methods run farthest from the action by default.
    /// <inheritdoc />
    public int Order { get; set; } = int.MinValue;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

因此,您应该对当前代码进行的唯一更改是将设置FooActionFilter.Orderint.MinValue

public class FooActionFilter : IActionFilter, IOrderedFilter
{
    public int Order => int.MinValue;

    //  ...
}
Run Code Online (Sandbox Code Playgroud)

现在,FooActionFilterControllerActionFilter具有相同的顺序。但是FooActionFilter是全局过滤器,ControllerActionFilter而是控制器级过滤器。这就是为什么FooActionFilter将基于以下语句首先执行的原因:

确定筛选器运行顺序时,Order属性胜过范围。过滤器首先按顺序排序,然后使用作用域断开联系