ASP.NET Core フィルターFilters in ASP.NET Core

作成者: Rick AndersonTom DykstraSteve SmithBy Rick Anderson, Tom Dykstra, and Steve Smith

ASP.NET Core MVC でフィルターを使用すると、要求処理パイプラインの特定のステージの前または後にコードを実行できます。Filters in ASP.NET Core MVC allow you to run code before or after specific stages in the request processing pipeline.

組み込みのフィルターでは次のようなタスクが処理されます。Built-in filters handle tasks such as:

  • 許可 (ユーザーに許可が与えられていないリソースの場合、アクセスを禁止する)。Authorization (preventing access to resources a user isn't authorized for).
  • すべての要求で HTTPS を使用する。Ensuring that all requests use HTTPS.
  • 応答キャッシュ (要求パイプラインを迂回し、キャッシュされている応答を返す)。Response caching (short-circuiting the request pipeline to return a cached response).

横断的な問題を処理するカスタム フィルターを作成できます。Custom filters can be created to handle cross-cutting concerns. フィルターでは、アクション間のコード重複を回避できます。Filters can avoid duplicating code across actions. たとえば、エラー処理例外フィルターではエラー処理を統合できます。For example, an error handling exception filter could consolidate error handling.

GitHub のサンプルを表示またはダウンロードしてくださいView or download sample from GitHub.

フィルターのしくみHow filters work

MVC のアクション呼び出しパイプライン内で実行されるフィルターは、フィルター パイプラインと呼ばれることがあります。Filters run within the MVC action invocation pipeline, sometimes referred to as the filter pipeline. フィルター パイプラインは、MVC が実行するアクションを選択した後に実行されます。The filter pipeline runs after MVC selects the action to execute.

要求は、他のミドルウェア、ルーティング ミドルウェア、アクション選択、および MVC のアクション呼び出しパイプラインを通じて処理されます。

フィルターの種類Filter types

フィルターの種類はそれぞれ、フィルター パイプラインの異なるステージで実行されます。Each filter type is executed at a different stage in the filter pipeline.

  • 承認フィルターは、最初に実行され、現在のユーザーが現在の要求に対して承認されているかどうかを判断するために使用されます。Authorization filters run first and are used to determine whether the current user is authorized for the current request. 要求が承認されていない場合は、パイプラインをショートサーキットできます。They can short-circuit the pipeline if a request is unauthorized.

  • リソース フィルターは、承認後、最初に要求を処理します。Resource filters are the first to handle a request after authorization. このフィルターは、残りのフィルター パイプラインの完了前と完了後にコードを実行できます。They can run code before the rest of the filter pipeline, and after the rest of the pipeline has completed. キャッシュを実装するか、そうでない場合はパフォーマンス上の理由からフィルター パイプラインをショートサーキットする場合に便利です。They're useful to implement caching or otherwise short-circuit the filter pipeline for performance reasons. モデル バインドに変化が及ぶように、モデル バインドの前に実行されます。They run before model binding, so they can influence model binding.

  • アクション フィルターは、個々のアクション メソッドが呼び出される直前と直後にコードを実行できます。Action filters can run code immediately before and after an individual action method is called. アクションに渡される引数とアクションから返される結果を操作するために使用できます。They can be used to manipulate the arguments passed into an action and the result returned from the action. アクション フィルターは Razor Pages ではサポートされていません。Action filters are not supported in Razor Pages.

  • 例外フィルターは、応答本文に何かが書き込まれる前に発生する未処理の例外にグローバル ポリシーを適用するために使用されます。Exception filters are used to apply global policies to unhandled exceptions that occur before anything has been written to the response body.

  • 結果フィルターは、個々のアクション結果の実行の直前と直後にコードを実行できます。Result filters can run code immediately before and after the execution of individual action results. アクション メソッドが正常に実行された場合にのみ実行されます。They run only when the action method has executed successfully. ビューまたはフォーマッタ実行を取り囲む必要があるロジックに便利です。They are useful for logic that must surround view or formatter execution.

これらのフィルターの種類がフィルター パイプラインでどのように連携しているかを、次の図に示します。The following diagram shows how these filter types interact in the filter pipeline.

要求は、承認フィルター、リソース フィルター、モデル バインド、アクション フィルター、アクションの実行とアクション結果の変換、例外フィルター、結果フィルター、結果の実行を介して処理されます。

実装Implementation

フィルターは、異なるインターフェイス定義を介して、同期と非同期の実装をサポートします。Filters support both synchronous and asynchronous implementations through different interface definitions.

パイプライン ステージの前後でコードを実行できる同期フィルターは、OnStageExecuting メソッドと OnStageExecuted メソッドを定義します。Synchronous filters that can run code both before and after their pipeline stage define OnStageExecuting and OnStageExecuted methods. たとえば、OnActionExecuting はアクション メソッドが呼び出される前に呼び出され、OnActionExecuted はアクション メソッドが返された後に呼び出されます。For example, OnActionExecuting is called before the action method is called, and OnActionExecuted is called after the action method returns.

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
        }
    }
}

非同期フィルターは、1 つの OnStageExecutionAsync メソッドを定義します。Asynchronous filters define a single OnStageExecutionAsync method. このメソッドは、フィルターのパイプライン ステージを実行する FilterTypeExecutionDelegate デリゲートを取得します。This method takes a FilterTypeExecutionDelegate delegate which executes the filter's pipeline stage. たとえば、ActionExecutionDelegate はアクション メソッドまたは次のアクション フィルターを呼び出すので、その呼び出しの前後でコードを実行できます。For example, ActionExecutionDelegate calls the action method or next action filter, and you can execute code before and after you call it.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            // do something before the action executes
            var resultContext = await next();
            // do something after the action executes; resultContext.Result will be set
        }
    }
}

1 つのクラスで複数のフィルター ステージに対してインターフェイスを実装することができます。You can implement interfaces for multiple filter stages in a single class. たとえば、ActionFilterAttribute クラスは、IActionFilterIResultFilter、およびそれらの非同期バージョンを実装します。For example, the ActionFilterAttribute class implements IActionFilter, IResultFilter, and their async equivalents.

注意

フィルター インターフェイスの同期と非同期バージョンの両方ではなく、いずれかを実装します。Implement either the synchronous or the async version of a filter interface, not both. フレームワークは、最初にフィルターが非同期インターフェイスを実装しているかどうかをチェックして、している場合はそれを呼び出します。The framework checks first to see if the filter implements the async interface, and if so, it calls that. していない場合は、同期インターフェイスのメソッドを呼び出します。If not, it calls the synchronous interface's method(s). 1 つのクラスに両方のインターフェイスを実装すると、非同期のメソッドのみが呼び出されます。If you were to implement both interfaces on one class, only the async method would be called. ActionFilterAttribute などの抽象クラスを使用する場合は、同期メソッドのみをオーバーライドするか、フィルターの種類ごとに非同期メソッドをオーバーライドします。When using abstract classes like ActionFilterAttribute you would override only the synchronous methods or the async method for each filter type.

IFilterFactoryIFilterFactory

IFilterFactoryIFilterMetadata を実装します。IFilterFactory implements IFilterMetadata. そのため、IFilterFactory インスタンスはフィルター パイプライン内の任意の場所で IFilterMetadata インスタンスとして使用できます。Therefore, an IFilterFactory instance can be used as an IFilterMetadata instance anywhere in the filter pipeline. フレームワークは、フィルターを呼び出す準備をする際に、それを IFilterFactory にキャストしようとします。When the framework prepares to invoke the filter, it attempts to cast it to an IFilterFactory. そのキャストが成功した場合、呼び出される IFilterMetadata インスタンスを作成するために CreateInstance メソッドが呼び出されます。If that cast succeeds, the CreateInstance method is called to create the IFilterMetadata instance that will be invoked. これにより、アプリの起動時に正確なフィルター パイプラインを明示的に設定する必要がないため、柔軟なデザインが可能になります。This provides a flexible design, since the precise filter pipeline doesn't need to be set explicitly when the app starts.

フィルターを作成するための別の方法として、独自の属性の実装で IFilterFactory を実装できます。You can implement IFilterFactory on your own attribute implementations as another approach to creating filters:

public class AddHeaderWithFactoryAttribute : Attribute, IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new InternalAddHeaderFilter();
    }

    private class InternalAddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "Internal", new string[] { "Header Added" });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

組み込みのフィルター属性Built-in filter attributes

フレームワークには、サブクラスを作成したりカスタマイズしたりできる組み込みの属性ベースのフィルターが含まれます。The framework includes built-in attribute-based filters that you can subclass and customize. たとえば、次の結果フィルターは、応答にヘッダーを追加します。For example, the following Result filter adds a header to the response.

using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class AddHeaderAttribute : ResultFilterAttribute
    {
        private readonly string _name;
        private readonly string _value;

        public AddHeaderAttribute(string name, string value)
        {
            _name = name;
            _value = value;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                _name, new string[] { _value });
            base.OnResultExecuting(context);
        }
    }
}

属性は、上記の例のように、フィルターが引数を受け取れるようにします。Attributes allow filters to accept arguments, as shown in the example above. この属性をコントローラーまたはアクション メソッドに追加し、HTTP ヘッダーの名前と値を指定します。You would add this attribute to a controller or action method and specify the name and value of the HTTP header:

[AddHeader("Author", "Steve Smith @ardalis")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header should be set.");
    }

Index アクションの結果を次に示します。応答ヘッダーが右下に表示されています。The result of the Index action is shown below - the response headers are displayed on the bottom right.

("Author Steve Smith " が含まれている) 応答ヘッダーを表示している Microsoft Edge の開発者ツール

フィルター インターフェイスのいくつかには対応する属性があり、カスタムの実装に基底クラスとして使用できます。Several of the filter interfaces have corresponding attributes that can be used as base classes for custom implementations.

フィルター属性:Filter attributes:

  • ActionFilterAttribute
  • ExceptionFilterAttribute
  • ResultFilterAttribute
  • FormatFilterAttribute
  • ServiceFilterAttribute
  • TypeFilterAttribute

TypeFilterAttributeServiceFilterAttribute については、この記事で後ほど説明します。TypeFilterAttribute and ServiceFilterAttribute are explained later in this article.

フィルターのスコープと実行の順序Filter scopes and order of execution

フィルターは、3 つのスコープのいずれかでパイプラインに追加することができます。A filter can be added to the pipeline at one of three scopes. 属性を使用して、特定のアクション メソッドまたはコントローラー クラスにフィルターを追加できます。You can add a filter to a particular action method or to a controller class by using an attribute. あるいは、すべてのコントローラーとアクションに対してフィルターをグローバル登録できます。Or you can register a filter globally for all controllers and actions. ConfigureServicesMvcOptions.Filters コレクションに追加することでフィルターをグローバルに追加できます。Filters are added globally by adding it to the MvcOptions.Filters collection in ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", 
            "Result filter added to MvcOptions.Filters")); // an instance
        options.Filters.Add(typeof(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}

実行の既定の順序Default order of execution

パイプラインの特定のステージに対して複数のフィルターがある場合に、スコープがフィルターの実行の既定の順序を決定します。When there are multiple filters for a particular stage of the pipeline, scope determines the default order of filter execution. グローバル フィルターがクラス フィルターを囲み、クラス フィルターがメソッド フィルターを囲みます。Global filters surround class filters, which in turn surround method filters. これは、入れ子人形のように、スコープが前のスコープを囲むたびに大きくなることから、"マトリョーシカ人形" 入れ子と呼ばれることがあります。This is sometimes referred to as "Russian doll" nesting, as each increase in scope is wrapped around the previous scope, like a nesting doll. 通常は、明示的に順序を決定しなくても、目的のオーバーライド動作が得られます。You generally get the desired overriding behavior without having to explicitly determine ordering.

この入れ子の結果として、フィルターの after コードが before コードと逆の順序で実行されます。As a result of this nesting, the after code of filters runs in the reverse order of the before code. シーケンスは次のようになります。The sequence looks like this:

  • グローバルに適用されるフィルターの before コードThe before code of filters applied globally
    • コントローラーに適用されるフィルターの before コードThe before code of filters applied to controllers
      • アクション メソッドに適用されるフィルターの before コードThe before code of filters applied to action methods
      • アクション メソッドに適用されるフィルターの after コードThe after code of filters applied to action methods
    • コントローラーに適用されるフィルターの after コードThe after code of filters applied to controllers
  • グローバルに適用されるフィルターの after コードThe after code of filters applied globally

同期アクション フィルターに対して呼び出されるフィルター メソッドの順序を示す例を次に示します。Here's an example that illustrates the order in which filter methods are called for synchronous Action filters.

シーケンスSequence フィルターのスコープFilter scope フィルター メソッドFilter method
11 GlobalGlobal OnActionExecuting
22 コントローラーController OnActionExecuting
33 メソッドMethod OnActionExecuting
44 メソッドMethod OnActionExecuted
55 コントローラーController OnActionExecuted
66 GlobalGlobal OnActionExecuted

このシーケンスが示すもの:This sequence shows:

  • メソッド フィルターは、コントローラー フィルター内で入れ子になります。The method filter is nested within the controller filter.
  • コントローラー フィルターは、グローバル フィルター内で入れ子になります。The controller filter is nested within the global filter.

別の言い方をすると、非同期フィルターの OnStageExecutionAsync メソッド内にいる場合、コードがスタックにある間に、厳密なスコープを持つすべてのフィルターが実行されます。To put it another way, if you're inside an async filter's OnStageExecutionAsync method, all of the filters with a tighter scope run while your code is on the stack.

注意

Controller 基底クラスから継承するすべてのコントローラーには、OnActionExecuting メソッドと OnActionExecuted メソッドが含まれます。Every controller that inherits from the Controller base class includes OnActionExecuting and OnActionExecuted methods. これらのメソッドは、特定のアクションに対して実行されるフィルターをラップします。OnActionExecuting はどのフィルターよりも前に呼び出され、OnActionExecuted はすべてのフィルターの後に呼び出されます。These methods wrap the filters that run for a given action: OnActionExecuting is called before any of the filters, and OnActionExecuted is called after all of the filters.

既定の順序のオーバーライドOverriding the default order

IOrderedFilter を実装することで、実行の既定の順序をオーバーライドできます。You can override the default sequence of execution by implementing IOrderedFilter. このインターフェイスは、実行の順序を決定するために、スコープよりも優先される Order プロパティを公開します。This interface exposes an Order property that takes precedence over scope to determine the order of execution. Order 値が低いフィルターがその before コードを、その Order の高い値よりも前に実行させます。A filter with a lower Order value will have its before code executed before that of a filter with a higher value of Order. Order 値が低いフィルターがその after コードを、その高い Order の値よりも後に実行させます。A filter with a lower Order value will have its after code executed after that of a filter with a higher Order value. Order プロパティは、コンストラクター パラメーターを使用して設定できます。You can set the Order property by using a constructor parameter:

[MyFilter(Name = "Controller Level Attribute", Order=1)]

上記の例で示されているのと同じ 3 つのアクション フィルターがあるが、コントローラーとグローバル フィルターの Order プロパティがそれぞれ 1 と 2 に設定されている場合、実行の順序が逆になります。If you have the same 3 Action filters shown in the preceding example but set the Order property of the controller and global filters to 1 and 2 respectively, the order of execution would be reversed.

シーケンスSequence フィルターのスコープFilter scope Order プロパティOrder property フィルター メソッドFilter method
11 メソッドMethod 00 OnActionExecuting
22 コントローラーController 11 OnActionExecuting
33 GlobalGlobal 22 OnActionExecuting
44 GlobalGlobal 22 OnActionExecuted
55 コントローラーController 11 OnActionExecuted
66 メソッドMethod 00 OnActionExecuted

フィルターの実行順序を決定するときに、Order プロパティはスコープより優先されます。The Order property trumps scope when determining the order in which filters will run. 最初に順序でフィルターが並べ替えられ、次に同じ順位の優先度を決めるためにスコープが使用されます。Filters are sorted first by order, then scope is used to break ties. 組み込みのフィルターはすべて IOrderedFilter を実装し、既定の Order 値を 0 に設定します。All of the built-in filters implement IOrderedFilter and set the default Order value to 0. 組み込みのフィルターの場合、Order をゼロ以外の値に設定しない限り、スコープによって順序が決定されます。For built-in filters, scope determines order unless you set Order to a non-zero value.

キャンセルとショート サーキットCancellation and short circuiting

フィルター メソッドに提供される context パラメーターで Result プロパティを設定することで、フィルター パイプラインを任意の時点でショート サーキットできます。You can short-circuit the filter pipeline at any point by setting the Result property on the context parameter provided to the filter method. たとえば、次のリソース フィルターは、パイプラインの残りの部分が実行されるのを防止します。For instance, the following Resource filter prevents the rest of the pipeline from executing.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ShortCircuitingResourceFilterAttribute : Attribute,
            IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.Result = new ContentResult()
            {
                Content = "Resource unavailable - header should not be set"
            };
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
}

次のコードでは、ShortCircuitingResourceFilterAddHeader の両方のフィルターが SomeResource アクション メソッドをターゲットにしています。In the following code, both the ShortCircuitingResourceFilter and the AddHeader filter target the SomeResource action method. ShortCircuitingResourceFilter:The ShortCircuitingResourceFilter:

  • これはリソース フィルターであり、AddHeader はアクション フィルターであるため、最初に実行されます。Runs first, because it's a Resource Filter and AddHeader is an Action Filter.
  • パイプラインの残りの部分は迂回されます。Short-circuits the rest of the pipeline.

そのため、SomeResource アクションの場合、AddHeader フィルターが実行されることはありません。Therefore the AddHeader filter never runs for the SomeResource action. ShortCircuitingResourceFilter が最初に実行された場合は、両方のフィルターがアクション メソッド レベルで適用されると、この動作が同じになります。This behavior would be the same if both filters were applied at the action method level, provided the ShortCircuitingResourceFilter ran first. そのフィルターの種類が原因で、あるいは Order プロパティの明示的な使用により、ShortCircuitingResourceFilter が最初に実行されます。The ShortCircuitingResourceFilter runs first because of its filter type, or by explicit use of Order property.

[AddHeader("Author", "Steve Smith @ardalis")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header should be set.");
    }

依存関係の挿入Dependency injection

フィルターは種類ごとまたはインスタンスごとに追加できます。Filters can be added by type or by instance. インスタンスを追加する場合、そのインスタンスがすべての要求に対して使用されます。If you add an instance, that instance will be used for every request. 種類を追加すると、種類でアクティブ化されます。つまり、要求ごとにインスタンスが作成され、依存関係の挿入 (DI) によってコンストラクターの依存関係が設定されます。If you add a type, it will be type-activated, meaning an instance will be created for each request and any constructor dependencies will be populated by dependency injection (DI). 種類ごとにフィルターを追加するのは、filters.Add(new TypeFilterAttribute(typeof(MyFilter))) に相当します。Adding a filter by type is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).

属性として実装され、コントローラー クラスまたはアクション メソッドに直接追加されるフィルターは、依存関係の挿入 (DI) によって提供されるコンストラクターの依存関係を持つことはできません。Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by dependency injection (DI). これは、属性には、適用される場所で提供される独自のコンストラクター パラメーターが必要だからです。This is because attributes must have their constructor parameters supplied where they're applied. これは、属性のしくみの制限です。This is a limitation of how attributes work.

フィルターに DI からアクセスする必要のある依存関係がある場合、サポートされているいくつかの方法があります。If your filters have dependencies that you need to access from DI, there are several supported approaches. 次のいずれかを使用して、クラスまたはアクション メソッドにフィルターを適用できます。You can apply your filter to a class or action method using one of the following:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • 属性に実装された IFilterFactoryIFilterFactory implemented on your attribute

注意

DI から取得できる依存関係の 1 つに、ロガーがあります。One dependency you might want to get from DI is a logger. ただし、必要な組み込みフレームワークのログ機能は既に提供されている場合があるため、ログ目的のためだけにフィルターを作成して使用することは避けてください。However, avoid creating and using filters purely for logging purposes, since the built-in framework logging features may already provide what you need. フィルターにログ記録を追加する場合は、MVC アクションやその他のフレームワーク イベントではなく、ビジネス ドメインの懸案事項や、フィルターに固有の動作を重視する必要があります。If you're going to add logging to your filters, it should focus on business domain concerns or behavior specific to your filter, rather than MVC actions or other framework events.

ServiceFilterAttributeServiceFilterAttribute

サービス フィルターの実装の種類は DI に登録されています。Service filter implementation types are registered in DI. ServiceFilterAttribute は DI からフィルターのインスタンスを取得します。A ServiceFilterAttribute retrieves an instance of the filter from DI. ServiceFilterAttribute のコンテナーに Startup.ConfigureServices を追加し、[ServiceFilter] 属性でそれを参照します。Add the ServiceFilterAttribute to the container in Startup.ConfigureServices, and reference it in a [ServiceFilter] attribute:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", 
            "Result filter added to MvcOptions.Filters")); // an instance
        options.Filters.Add(typeof(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}
[ServiceFilter(typeof(AddHeaderFilterWithDi))]
public IActionResult Index()
{
    return View();
}

ServiceFilterAttribute を使用する場合、IsReusable を設定すると、フィルター インスタンスが作成された要求の範囲外で再利用できる可能性があることのヒントになります。When using ServiceFilterAttribute, setting IsReusable is a hint that the filter instance may be reused outside of the request scope it was created within. このフレームワークで、フィルターの 1 インスタンスが作成されたり、今後のある時点で DI コンテナーからフィルターが再要求されたりするという保証はありません。The framework provides no guarantees that a single instance of the filter will be created or the filter will not be re-requested from the DI container at some later point. シングルトン以外で有効期間があるサービスに依存するフィルターを使用するときは、IsReusable の使用は避けてください。Avoid using IsReusable when using a filter that depends on services with a lifetime other than singleton.

フィルターの種類を登録せずに ServiceFilterAttribute を使用すると、例外が発生します。Using ServiceFilterAttribute without registering the filter type results in an exception:

System.InvalidOperationException: No service for type
'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.

ServiceFilterAttribute は、IFilterFactory を実装します。ServiceFilterAttribute implements IFilterFactory. IFilterFactory は、IFilterMetadata インスタンスを作成するために CreateInstance メソッドを公開します。IFilterFactory exposes the CreateInstance method for creating an IFilterMetadata instance. CreateInstance メソッドは、サービス コンテナー (DI) から、指定した型を読み込みます。The CreateInstance method loads the specified type from the services container (DI).

TypeFilterAttributeTypeFilterAttribute

TypeFilterAttributeServiceFilterAttribute と似ていますが、その型は DI コンテナーから直接解決されません。TypeFilterAttribute is similar to ServiceFilterAttribute, but its type isn't resolved directly from the DI container. Microsoft.Extensions.DependencyInjection.ObjectFactory を使って型をインスタンス化します。It instantiates the type by using Microsoft.Extensions.DependencyInjection.ObjectFactory.

この違いにより:Because of this difference:

  • TypeFilterAttribute を利用して参照される型は、先にコンテナーに登録する必要がありません。Types that are referenced using the TypeFilterAttribute don't need to be registered with the container first. コンテナーによって依存関係が満たされています。They do have their dependencies fulfilled by the container.
  • TypeFilterAttribute は必要に応じて、型のコンストラクター引数を受け取ることができます。TypeFilterAttribute can optionally accept constructor arguments for the type.

TypeFilterAttribute を使用する場合、IsReusable を設定すると、フィルター インスタンスが作成された要求の範囲外で再利用できる可能性があることのヒントになります。When using TypeFilterAttribute, setting IsReusable is a hint that the filter instance may be reused outside of the request scope it was created within. このフレームワークで、フィルターの 1 インスタンスが作成されるという保証はありません。The framework provides no guarantees that a single instance of the filter will be created. シングルトン以外で有効期間があるサービスに依存するフィルターを使用するときは、IsReusable の使用は避けてください。Avoid using IsReusable when using a filter that depends on services with a lifetime other than singleton.

次の例は、TypeFilterAttribute を使用して、型に引数を渡す方法を示しています。The following example demonstrates how to pass arguments to a type using TypeFilterAttribute:

[TypeFilter(typeof(LogConstantFilter),
    Arguments = new object[] { "Method 'Hi' called" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}
public class LogConstantFilter : IActionFilter
{
    private readonly string _value;
    private readonly ILogger<LogConstantFilter> _logger;

    public LogConstantFilter(string value, ILogger<LogConstantFilter> logger)
    {
        _logger = logger;
        _value = value;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation(_value);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    { }
}

属性に実装された IFilterFactoryIFilterFactory implemented on your attribute

次のようなフィルターがある場合:If you have a filter that:

  • 引数を必要としない。Doesn't require any arguments.
  • DI で満たす必要があるコンストラクター依存関係がある。Has constructor dependencies that need to be filled by DI.

[TypeFilter(typeof(FilterType))] の代わりに、クラスとメソッドで独自の名前付き属性を使用できます。You can use your own named attribute on classes and methods instead of [TypeFilter(typeof(FilterType))]). 次のフィルターは、これを実装する方法を示しています。The following filter shows how this can be implemented:

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl))
    {
    }

    private class SampleActionFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;
        public SampleActionFilterImpl(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _logger.LogInformation("Business action starting...");
            // perform some business logic work

        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // perform some business logic work
            _logger.LogInformation("Business action completed.");
        }
    }
}

このフィルターは、[TypeFilter] または [ServiceFilter] を使用する代わりに、[SampleActionFilter] 構文を使用して、クラスまたはメソッドに適用することができます。This filter can be applied to classes or methods using the [SampleActionFilter] syntax, instead of having to use [TypeFilter] or [ServiceFilter].

承認フィルターAuthorization filters

承認フィルター:Authorization filters:

  • アクション メソッドへのアクセスを制御します。Control access to action methods.
  • フィルター パイプライン内で実行される最初のフィルターです。Are the first filters to be executed within the filter pipeline.
  • before メソッドが与えられ、after メソッドは与えられません。Have a before method, but no after method.

独自の承認フレームワークを記述している場合は、カスタムの承認フィルターを記述するだけで済みます。You should only write a custom authorization filter if you are writing your own authorization framework. カスタム フィルターを記述するよりも、独自の承認ポリシーを構成するか、カスタム承認ポリシーを記述することを選びます。Prefer configuring your authorization policies or writing a custom authorization policy over writing a custom filter. 組み込みフィルターの実装は、認証システムを呼び出すことしかしません。The built-in filter implementation is just responsible for calling the authorization system.

例外を処理するものがないため (例外フィルターは例外を処理しません)、承認フィルター内で例外をスローしないでください。You shouldn't throw exceptions within authorization filters, since nothing will handle the exception (exception filters won't handle them). 例外が発生した場合、チャレンジ発行を検討してください。Consider issuing a challenge when an exception occurs.

承認の詳細については、こちらを参照してください。Learn more about Authorization.

リソース フィルターResource filters

  • IResourceFilter または IAsyncResourceFilter のインターフェイスを実装します。Implement either the IResourceFilter or IAsyncResourceFilter interface,
  • その実行では、多くのフィルター パイプラインがラップされます。Their execution wraps most of the filter pipeline.
  • 承認フィルターのみ、リソース フィルターの前に実行されます。Only Authorization filters run before Resource filters.

リソース フィルターは、要求が行っている作業の大部分を迂回する場合に便利です。Resource filters are useful to short-circuit most of the work a request is doing. たとえば、フィルターをキャッシュすることで、応答がキャッシュ内にある場合に、パイプラインの残りの部分を回避することができます。For example, a caching filter can avoid the rest of the pipeline if the response is in the cache.

前に示したリソース フィルターのショート サーキットは、リソース フィルターの一例です。The short circuiting resource filter shown earlier is one example of a resource filter. もう 1 つの例が DisableFormValueModelBindingAttribute です。Another example is DisableFormValueModelBindingAttribute:

  • モデル バインドがフォーム データにアクセスすることを禁止します。It prevents model binding from accessing the form data.
  • 大きなファイルのアップロードや、メモリにフォームが読み込まれないようにするときに便利です。It's useful for large file uploads and want to prevent the form from being read into memory.

アクション フィルターAction filters

重要

アクション フィルターは Razor Pages に適用されませんAction filters do not apply to Razor Pages. Razor Pages では IPageFilterIAsyncPageFilter がサポートされています。Razor Pages supports IPageFilter and IAsyncPageFilter . 詳細については、Razor ページのフィルター メソッドに関するページを参照してください。For more information, see Filter methods for Razor Pages.

アクション フィルター:Action filters:

  • IActionFilter または IAsyncActionFilter のインターフェイスを実装します。Implement either the IActionFilter or IAsyncActionFilter interface.
  • この実行はアクション メソッドの実行を取り囲みます。Their execution surrounds the execution of action methods.

サンプルのアクション フィルターを次に示します。Here's a sample action filter:

public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // do something before the action executes
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // do something after the action executes
    }
}

ActionExecutingContext では次のプロパティが提供されます。The ActionExecutingContext provides the following properties:

  • ActionArguments: アクションへの入力を操作できます。ActionArguments - lets you manipulate the inputs to the action.
  • Controller: コントローラー インスタンスを操作できます。Controller - lets you manipulate the controller instance.
  • Result: これを設定することで、アクション メソッドと後続のアクション フィルターの実行をショートサーキットします。Result - setting this short-circuits execution of the action method and subsequent action filters. 例外をスローすることで、アクション メソッドと後続のアクション フィルターの実行も防止できますが、成功の結果ではなく、エラーとして扱われます。Throwing an exception also prevents execution of the action method and subsequent filters, but is treated as a failure instead of a successful result.

ActionExecutedContext は、ControllerResult に加え、次のプロパティを提供します。The ActionExecutedContext provides Controller and Result plus the following properties:

  • Canceled: 別のフィルターによってアクションの実行がショートサーキットされた場合は、true になります。Canceled - will be true if the action execution was short-circuited by another filter.
  • Exception: アクションまたは後続のアクション フィルターが例外をスローした場合は、null 以外になります。Exception - will be non-null if the action or a subsequent action filter threw an exception. このプロパティを null に設定すると、例外を効果的に '処理' でき、Result がアクション メソッドから通常に返されたかのように実行されます。Setting this property to null effectively 'handles' an exception, and Result will be executed as if it were returned from the action method normally.

IAsyncActionFilter の場合、ActionExecutionDelegate の呼び出しによって:For an IAsyncActionFilter, a call to the ActionExecutionDelegate:

  • 後続のすべてのアクション フィルターとアクション メソッドが実行されます。Executes any subsequent action filters and the action method.
  • ActionExecutedContext が返されます。returns ActionExecutedContext.

ショートサーキットするには、ActionExecutingContext.Result をいくつかの結果インスタンスに割り当てます。ActionExecutionDelegate は呼び出さないでください。To short-circuit, assign ActionExecutingContext.Result to some result instance and don't call the ActionExecutionDelegate.

フレームワークは、サブクラス化できる抽象 ActionFilterAttribute を提供します。The framework provides an abstract ActionFilterAttribute that you can subclass.

アクション フィルターを使用してモデルの状態を検証し、状態が無効な場合に、エラーを返すことができます。You can use an action filter to validate model state and return any errors if the state is invalid:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }
}

OnActionExecuted メソッドは、アクション メソッドの後に実行され、ActionExecutedContext.Result プロパティを通じてアクションの結果を確認および操作することができます。The OnActionExecuted method runs after the action method and can see and manipulate the results of the action through the ActionExecutedContext.Result property. 別のフィルターによってアクションの実行がショートサーキットされた場合、ActionExecutedContext.Canceled は true に設定されます。ActionExecutedContext.Canceled will be set to true if the action execution was short-circuited by another filter. アクションまたは後続のアクション フィルターが例外をスローした場合、ActionExecutedContext.Exception は null 以外の値に設定されます。ActionExecutedContext.Exception will be set to a non-null value if the action or a subsequent action filter threw an exception. ActionExecutedContext.Exception を null に設定すると:Setting ActionExecutedContext.Exception to null:

  • 例外が効果的に '処理' されます。Effectively 'handles' an exception.
  • ActionExecutedContext.Result は、アクション メソッドから通常どおり返されたかのように実行されます。ActionExecutedContext.Result is executed as if it were returned normally from the action method.

例外フィルターException filters

例外フィルターは、IExceptionFilter または IAsyncExceptionFilter のいずれかのインターフェイスを実装します。Exception filters implement either the IExceptionFilter or IAsyncExceptionFilter interface. これを使用して、アプリの共通のエラー処理ポリシーを実装できます。They can be used to implement common error handling policies for an app.

次の例外フィルターのサンプルでは、カスタムの開発エラー ビューを使用して、アプリの開発中に発生する例外に関する詳細を表示します。The following sample exception filter uses a custom developer error view to display details about exceptions that occur when the app is in development:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly IHostingEnvironment _hostingEnvironment;
    private readonly IModelMetadataProvider _modelMetadataProvider;

    public CustomExceptionFilterAttribute(
        IHostingEnvironment hostingEnvironment,
        IModelMetadataProvider modelMetadataProvider)
    {
        _hostingEnvironment = hostingEnvironment;
        _modelMetadataProvider = modelMetadataProvider;
    }

    public override void OnException(ExceptionContext context)
    {
        if (!_hostingEnvironment.IsDevelopment())
        {
            // do nothing
            return;
        }
        var result = new ViewResult {ViewName = "CustomError"};
        result.ViewData = new ViewDataDictionary(_modelMetadataProvider,context.ModelState);
        result.ViewData.Add("Exception", context.Exception);
        // TODO: Pass additional detailed data via ViewData
        context.Result = result;
    }
}

例外フィルター:Exception filters:

  • before イベントと after イベントが与えられません。Don't have before and after events.
  • OnException または OnExceptionAsync を実装します。Implement OnException or OnExceptionAsync.
  • コントローラーの作成、モデル バインド、アクション フィルター、またはアクション メソッドで発生する未処理の例外を処理します。Handle unhandled exceptions that occur in controller creation, model binding, action filters, or action methods.
  • リソース フィルター、結果フィルター、または MVC 結果の実行で発生した例外はキャッチしません。Do not catch exceptions that occur in Resource filters, Result filters, or MVC Result execution.

例外を処理するには、ExceptionContext.ExceptionHandled プロパティを true に設定するか、応答を記述します。To handle an exception, set the ExceptionContext.ExceptionHandled property to true or write a response. これにより、例外の伝達を停止します。This stops propagation of the exception. 例外フィルターでは、例外を "成功" に変えられません。An Exception filter can't turn an exception into a "success". これができるのは、アクション フィルターだけです。Only an Action filter can do that.

注意

ASP.NET Core 1.1 では、ExceptionHandled を true に設定し、さらに応答を記述すると、応答が送信されません。In ASP.NET Core 1.1, the response isn't sent if you set ExceptionHandled to true and write a response. そのシナリオでは、ASP.NET Core 1.0 は応答を送信し、ASP.NET Core 1.1.2 は 1.0 の動作に戻ります。In that scenario, ASP.NET Core 1.0 does send the response, and ASP.NET Core 1.1.2 will return to the 1.0 behavior. 詳細については、GitHub リポジトリで「issue #5594」を参照してください。For more information, see issue #5594 in the GitHub repository.

例外フィルター:Exception filters:

  • MVC アクション内で発生する例外のトラップに適しています。Are good for trapping exceptions that occur within MVC actions.
  • エラー処理ミドルウェアほど柔軟ではありません。Are not as flexible as error handling middleware.

例外処理にはミドルウェアを選択してください。Prefer middleware for exception handling. 選択された MVC アクションに基づき、異なる方法でエラーを処理する必要がある場合にのみ、例外フィルターを使用します。Use exception filters only where you need to do error handling differently based on which MVC action was chosen. たとえば、ご利用のアプリには、API エンドポイントとビュー/HTML の両方に対するアクション メソッドがある場合があります。For example, your app might have action methods for both API endpoints and for views/HTML. API エンドポイントは、JSON としてのエラー情報を返す可能性がある一方で、ビュー ベースのアクションがエラー ページを HTML として返す可能性があります。The API endpoints could return error information as JSON, while the view-based actions could return an error page as HTML.

ExceptionFilterAttribute はサブクラス化できます。The ExceptionFilterAttribute can be subclassed.

結果フィルターResult filters

  • インターフェイスを実装します:Implement an interface:
    • IResultFilter または IAsyncResultFilterIResultFilter or IAsyncResultFilter.
    • IAlwaysRunResultFilter または IAsyncAlwaysRunResultFilterIAlwaysRunResultFilter or IAsyncAlwaysRunResultFilter
  • この実行はアクション結果の実行を取り囲みます。Their execution surrounds the execution of action results.

IResultFilter および IAsyncResultFilterIResultFilter and IAsyncResultFilter

HTTP ヘッダーを追加する結果フィルターの例を次に示します。Here's an example of a Result filter that adds an HTTP header.

public class AddHeaderFilterWithDi : IResultFilter
{
    private ILogger _logger;
    public AddHeaderFilterWithDi(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderFilterWithDi>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation($"Header added: {headerName}");
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has already begun.
    }
}

実行されている結果の種類は、対象のアクションに依存します。The kind of result being executed depends on the action in question. ビューを返す MVC アクションには、実行されている ViewResult の一部として、すべての razor 処理が含まれます。An MVC action returning a view would include all razor processing as part of the ViewResult being executed. API メソッドは、結果の実行の一部としていくつかのシリアル化を実行できます。An API method might perform some serialization as part of the execution of the result. アクション結果に関する詳細は、こちらを参照してください。Learn more about action results

結果フィルターは、アクションまたはアクション フィルターがアクションの結果を生成するときに、成功した結果に対してのみ実行されます。Result filters are only executed for successful results - when the action or action filters produce an action result. 例外フィルターが例外を処理するときには、結果フィルターは実行されません。Result filters are not executed when exception filters handle an exception.

OnResultExecuting メソッドは、ResultExecutingContext.Cancel を true に設定することで、アクションの結果と後続の結果フィルターの実行をショートサーキットできます。The OnResultExecuting method can short-circuit execution of the action result and subsequent result filters by setting ResultExecutingContext.Cancel to true. ショートサーキットする場合は、通常、空の応答が生成されないように応答オブジェクトに記述する必要があります。You should generally write to the response object when short-circuiting to avoid generating an empty response. 例外をスローする:Throwing an exception will:

  • アクション結果と後続フィルターの実行が回避されます。Prevent execution of the action result and subsequent filters.
  • 結果は成功ではなく、失敗として処理されます。Be treated as a failure instead of a successful result.

OnResultExecuted メソッドを実行するときに、応答がクライアントに送信され、(例外がスローされない限り) それ以上変更できない可能性があます。When the OnResultExecuted method runs, the response has likely been sent to the client and cannot be changed further (unless an exception was thrown). 別のフィルターによってアクションの結果の実行がショートサーキットされた場合、ResultExecutedContext.Canceled は true に設定されます。ResultExecutedContext.Canceled will be set to true if the action result execution was short-circuited by another filter.

アクションの結果または後続の結果フィルターが例外をスローした場合、ResultExecutedContext.Exception は null 以外の値に設定されます。ResultExecutedContext.Exception will be set to a non-null value if the action result or a subsequent result filter threw an exception. Exception を null に設定すると、例外を効果的に '処理' でき、パイプラインの後方で MVC によって例外が再スローされることを防げます。Setting Exception to null effectively 'handles' an exception and prevents the exception from being rethrown by MVC later in the pipeline. 結果フィルター内の例外を処理しているときに、応答にどのデータも書き込めない場合があります。When you're handling an exception in a result filter, you might not be able to write any data to the response. アクションの結果がその実行の途中でスローして、クライアントに対してはヘッダーが既にフラッシュされている場合、エラー コードを送信するための信頼性の高いメカニズムはありません。If the action result throws partway through its execution, and the headers have already been flushed to the client, there's no reliable mechanism to send a failure code.

IAsyncResultFilter の場合、ResultExecutionDelegate での await next への呼び出しは、後続のすべての結果フィルターとアクションの結果を実行します。For an IAsyncResultFilter a call to await next on the ResultExecutionDelegate executes any subsequent result filters and the action result. ショートサーキットするには、ResultExecutingContext.Cancel を true に設定します。ResultExecutionDelegate は呼び出さないでください。To short-circuit, set ResultExecutingContext.Cancel to true and don't call the ResultExecutionDelegate.

フレームワークは、サブクラス化できる抽象 ResultFilterAttribute を提供します。The framework provides an abstract ResultFilterAttribute that you can subclass. 前に示した AddHeaderAttribute クラスは、結果フィルター属性の一例です。The AddHeaderAttribute class shown earlier is an example of a result filter attribute.

IAlwaysRunResultFilter および IAsyncAlwaysRunResultFilterIAlwaysRunResultFilter and IAsyncAlwaysRunResultFilter

IAlwaysRunResultFilter および IAsyncAlwaysRunResultFilter インターフェイスでは、アクションの結果に対して実行される IResultFilter の実装が宣言されます。The IAlwaysRunResultFilter and IAsyncAlwaysRunResultFilter interfaces declare an IResultFilter implementation that runs for action results. IExceptionFilter または IAuthorizationFilter が適用されて応答が省略されない限り、アクションの結果に対してそのフィルターが適用されます。The filter is applied to an action result unless an IExceptionFilter or IAuthorizationFilter applies and short-circuits the response.

つまり、これらの "常に実行" フィルターは、例外または承認フィルターによってそれが省略される場合を除き、常に実行されます。In other words, these "always run" filters, always run, except when an exception or authorization filter short-circuits them. IExceptionFilterIAuthorizationFilter 以外のフィルターによってそれらが省略されることはありません。Filters other than IExceptionFilter and IAuthorizationFilter don't short circuit them.

たとえば、次のフィルターは常に実行され、コンテンツ ネゴシエーションが失敗した場合に "422 処理不可エンティティ" 状態コードを使ってアクションの結果 (ObjectResult) を設定します。For example, the following filter always runs and sets an action result (ObjectResult) with a 422 Unprocessable Entity status code when content negotiation fails:

public class UnprocessableResultFilter : Attribute, IAlwaysRunResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is StatusCodeResult statusCodeResult &&
            statusCodeResult.StatusCode == 415)
        {
            context.Result = new ObjectResult("Can't process this!")
            {
                StatusCode = 422,
            };
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
    }
}

フィルター パイプラインでのミドルウェアの使用Using middleware in the filter pipeline

リソース フィルターは、パイプラインの後方で登場するすべての実行を囲む点で、ミドルウェアのように機能します。Resource filters work like middleware in that they surround the execution of everything that comes later in the pipeline. ただし、フィルターは MVC の一部である点がミドルウェアとは異なります。つまり、フィルターには MVC コンテキストとコンストラクトへのアクセスがあります。But filters differ from middleware in that they're part of MVC, which means that they have access to MVC context and constructs.

ASP.NET Core 1.1 では、フィルター パイプラインでミドルウェアを使用できます。In ASP.NET Core 1.1, you can use middleware in the filter pipeline. MVC ルート データへのアクセスを必要とする、または特定のコントローラーまたはアクションを実行する必要があるミドルウェア コンポーネントがある場合は、ミドルウェアを使用できます。You might want to do that if you have a middleware component that needs access to MVC route data, or one that should run only for certain controllers or actions.

ミドルウェアをフィルターとして使用するには、フィルター パイプラインに挿入するミドルウェアを指定する Configure メソッドを使用して型を作成します。To use middleware as a filter, create a type with a Configure method that specifies the middleware that you want to inject into the filter pipeline. ローカリゼーション ミドルウェアを使用して要求の現在のカルチャを確立する例を次に示します。Here's an example that uses the localization middleware to establish the current culture for a request:

public class LocalizationPipeline
{
    public void Configure(IApplicationBuilder applicationBuilder)
    {
        var supportedCultures = new[]
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr")
        };

        var options = new RequestLocalizationOptions
        {

            DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        };
        options.RequestCultureProviders = new[] 
            { new RouteDataRequestCultureProvider() { Options = options } };

        applicationBuilder.UseRequestLocalization(options);
    }
}

MiddlewareFilterAttribute を使用して、選択したコントローラーまたはアクションに対してミドルウェアを実行することも、グローバルにミドルウェアを実行することもできます。You can then use the MiddlewareFilterAttribute to run the middleware for a selected controller or action or globally:

[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData()
{
    return Content($"CurrentCulture:{CultureInfo.CurrentCulture.Name},"
        + $"CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");
}

ミドルウェア フィルターは、フィルター パイプラインのリソース フィルターと同じステージ (モデル バインドの前、残りのパイプラインの後) で実行されます。Middleware filters run at the same stage of the filter pipeline as Resource filters, before model binding and after the rest of the pipeline.

次の操作Next actions