フィルターの概要と適用タイミング
フィルターパイプラインは、ASP.NET Coreアプリケーションにおけるリクエスト処理のライフサイクルにおいて、特定のポイントで追加処理を実行するための仕組みです。主にMVCコントローラーやRazor Pagesで使用され、共通処理の抽出や横断的関心事の扱いに役立ちます。
フィルターの種類と実行順序
フィルターは以下の6種類に分類され、それぞれ異なるタイミングで実行されます:
- 認証フィルター - リクエストの認証状態を検証
- リソースフィルター - モデルバインディング前後の処理を担当
- アクションフィルター - アクションメソッド実行前後の処理を実行
- ページフィルター - Razor Pages専用のフィルター
- 例外フィルター - 処理中に発生した例外を捕捉
- 結果フィルター - アクション結果の実行前後に処理
フィルター実装例
以下はリソースフィルターの実装例です:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CustomResourceFilter : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext ctx)
{
// リクエスト処理前のロジック
Console.WriteLine("処理開始");
}
public void OnResourceExecuted(ResourceExecutedContext ctx)
{
// リクエスト処理後のロジック
Console.WriteLine("処理完了");
}
}
フィルターの適用方法
フィルターは以下のスコープで適用できます:
- グローバルスコープ - 全コントローラー/ページに適用
- コントローラースコープ - 特定コントローラーの全アクションに適用
- アクションスコープ - 個別のアクションメソッドに適用
- ページスコープ - Razor Pageに適用
フィルターとミドルウェアの選択基準
フィルターとミドルウェアの使い分けは以下の基準で判断します:
- MVC/Razor Pages固有の機能が必要な場合 → フィルター
- アプリケーション全体の横断的処理が必要な場合 → ミドルウェア
- モデルバインディングやアクション結果へのアクセスが必要な場合 → フィルター
- 低レベルなHTTPコンテキスト操作が必要な場合 → ミドルウェア
実践的なフィルター活用例
フィルターを使用してコントローラーの共通処理を抽出する例:
public class ValidationFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
public void OnActionExecuted(ActionExecutedContext context) { }
}
// コントローラーでの使用例
[ApiController]
[Route("api/products")]
[TypeFilter(typeof(ValidationFilter))]
public class ProductsController : ControllerBase
{
[HttpPost]
public IActionResult CreateProduct(ProductDto product)
{
// バリデーションはフィルターで自動処理
return Ok(product);
}
}
依存性注入の活用
フィルターで依存性注入を使用する例:
public class LoggingFilter : IActionFilter
{
private readonly ILogger<LoggingFilter> _logger;
public LoggingFilter(ILogger<LoggingFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("アクション実行開始: {ActionName}",
context.ActionDescriptor.DisplayName);
}
public void OnActionExecuted(ActionExecutedContext context) { }
}