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のようなゼロ以外の値を設定したりしても、実行順序に影響はないようです。
私の質問:グローバルフィルターにOnActionExecuting
beforeを実行させるにはどうすればよいですか(ベース)コントローラーのOnActionExecuting
?
あと少しです。小さな間違いは、コントローラーフィルターの実行のデフォルトの順序が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.Order
をint.MinValue
に設定することです。
public class FooActionFilter : IActionFilter, IOrderedFilter
{
public int Order => int.MinValue;
// ...
}
FooActionFilter
とControllerActionFilter
の順序が同じになりました。ただし、FooActionFilter
はグローバルフィルターですが、ControllerActionFilter
はコントローラーレベルのフィルターです。 このステートメント に基づいて、FooActionFilter
が最初に実行されるのはそのためです。
Orderプロパティは、フィルターが実行される順序を決定するときにスコープよりも優先されます。フィルターは最初に順序で並べ替えられます、次にスコープを使用して結合を解除します。