メインコンテンツまでスキップ

Middleware(ミドルウェア)

ミドルウェアとは

ASP.NET Coreにおける**ミドルウェア(Middleware)**は、HTTPリクエストとレスポンスを処理するためのアプリケーションパイプラインに組み込まれるソフトウェアコンポーネントです。

各ミドルウェアコンポーネントは以下の役割を持ちます:

  1. リクエストをパイプライン内の次のコンポーネントに渡すかどうかを選択する。
  2. パイプラインの次のコンポーネントが呼び出されるに処理を実行する。

Middleware Pipeline (出典: Microsoft Learn)

リクエストパイプライン

ASP.NET Coreのリクエストパイプラインは、一連のミドルウェアデリゲートとして構成されます。これらは Program.csWebApplication ビルダーを使用して構成されます。

処理の流れ

  1. リクエストが届くと、登録された順序で最初のミドルウェアが呼び出されます。
  2. ミドルウェアは処理を行い、next() を呼び出して次のミドルウェアに制御を渡します。
  3. これを繰り返し、最後のミドルウェア(ターミナルミドルウェア)まで到達します。
  4. 最後のミドルウェアが処理を終えると、制御は逆順で前のミドルウェアに戻っていきます(レスポンス処理)。

順序の重要性

ミドルウェアの登録順序は非常に重要です。例えば、認証(Authentication)ミドルウェアは、認可(Authorization)ミドルウェアの前に実行される必要があります。

一般的な順序の例:

  1. 例外ハンドラー (UseExceptionHandler)
  2. HSTS (UseHsts)
  3. HTTPSリダイレクト (UseHttpsRedirection)
  4. 静的ファイル (UseStaticFiles)
  5. ルーティング (UseRouting)
  6. CORS (UseCors)
  7. 認証 (UseAuthentication)
  8. 認可 (UseAuthorization)
  9. エンドポイント (MapControllers, MapRazorPages など)

基本的な実装方法

Run

Run はパイプラインの終端(ターミナル)を定義します。これ以降のミドルウェアは実行されません。

app.Run(async context =>
{
await context.Response.WriteAsync("Hello from terminal middleware!");
});

Use

Use はパイプラインの途中に処理を挿入します。next パラメータを使用して次のミドルウェアを呼び出します。

app.Use(async (context, next) =>
{
// 次のミドルウェアを呼び出す前の処理
Console.WriteLine("Before next middleware");

await next.Invoke();

// 次のミドルウェアから戻ってきた後の処理
Console.WriteLine("After next middleware");
});

Map

Map はリクエストパスに基づいてパイプラインを分岐させます。

app.Map("/branch", branchApp =>
{
branchApp.Run(async context =>
{
await context.Response.WriteAsync("This is a branch pipeline.");
});
});

カスタムミドルウェアの作成

再利用可能なミドルウェアを作成する場合、クラスとして定義するのが一般的です。

規約ベースのミドルウェア

特定のインターフェースを実装する必要はありませんが、以下の規約に従う必要があります。

  1. RequestDelegate 型の引数を持つパブリックコンストラクターを持つ。
  2. HttpContext を引数に取り、Task を返す Invoke または InvokeAsync という名前のパブリックメソッドを持つ。
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;

public RequestLoggingMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");

await _next(context);

Console.WriteLine($"Response: {context.Response.StatusCode}");
}
}

拡張メソッドの作成

IApplicationBuilder に対する拡張メソッドを作成して、登録を簡単にします。

public static class RequestLoggingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}

使用方法

Program.cs で登録します。

var app = builder.Build();

app.UseRequestLogging(); // カスタムミドルウェアの使用

app.Run();

IMiddleware インターフェース

IMiddleware インターフェースを実装する方法もあります。この場合、ミドルウェアはDIコンテナに登録する必要があります(通常は Transient または Scoped)。

public class FactoryActivatedMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// 処理
await next(context);
}
}

登録:

builder.Services.AddTransient<FactoryActivatedMiddleware>();

// ...

app.UseMiddleware<FactoryActivatedMiddleware>();

標準的なミドルウェア

ASP.NET Coreには多くの組み込みミドルウェアが用意されています。

ミドルウェア説明
UseStaticFiles静的ファイル(HTML, CSS, JS, 画像など)を提供します。
UseRoutingリクエストURLをエンドポイントにマッチングさせます。
UseAuthenticationユーザーのIDを検証します(ログイン処理など)。
UseAuthorizationユーザーがリソースにアクセスする権限を持っているか確認します。
UseCorsCross-Origin Resource Sharing (CORS) を構成します。
UseSessionセッション状態を管理します。
UseResponseCachingレスポンスのキャッシュをサポートします。

まとめ

  • ミドルウェアはリクエストパイプラインを構成する部品です。
  • 登録順序が動作に大きく影響します。
  • Use, Run, Map を組み合わせてパイプラインを構築します。
  • 複雑なロジックはクラスベースのカスタムミドルウェアとしてカプセル化することが推奨されます。