web-dev-qa-db-ja.com

ASP.NET Coreで、コントローラーのOnActionExecutingの前にグローバルフィルターを実行します。

ASP.NET Core 2.0アプリケーションで、コントローラーのバリアントを実行する前にグローバルフィルターのOnActionExecutingを実行しようとしています。予想される動作は、前にグローバルで何かを準備し、結果の値をコントローラーに渡すことができることです。ただし、現在の動作では、実行順序は設計によって逆になっています。

ドキュメントは デフォルトの実行順序 について教えてくれます:

Controller基本クラスから継承するすべてのコントローラーには、OnActionExecutingメソッドとOnActionExecutedメソッドが含まれます。これらのメソッドは、特定のアクションに対して実行されるフィルターをラップします。OnActionExecutingはいずれかのフィルターの前に呼び出され、OnActionExecutedはすべてのフィルターの後に呼び出されます。

これにより、コントローラーの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);
    }
}

このフィルターは、起動時に次のように登録されます。

services.AddMvc(options => options.Filters.Add(new FooActionFilter()));

最後に、私の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();
    }
}

Orderを0に設定したり、-1のようなゼロ以外の値を設定したりしても、実行順序に影響はないようです。

私の質問:グローバルフィルターにOnActionExecutingbeforeを実行させるにはどうすればよいですか(ベース)コントローラーのOnActionExecuting

14
Juliën

あと少しです。小さな間違いは、コントローラーフィルターの実行のデフォルトの順序が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;

    // ...
}

したがって、現在のコードに対して行う必要がある唯一の変更は、FooActionFilter.Orderint.MinValueに設定することです。

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

    //  ...
}

FooActionFilterControllerActionFilterの順序が同じになりました。ただし、FooActionFilterはグローバルフィルターですが、ControllerActionFilterはコントローラーレベルのフィルターです。 このステートメント に基づいて、FooActionFilterが最初に実行されるのはそのためです。

Orderプロパティは、フィルターが実行される順序を決定するときにスコープよりも優先されます。フィルターは最初に順序で並べ替えられます、次にスコープを使用して結合を解除します

9
CodeFuller