0Pricing
C# Academy · レッスン

ASP.NET Coreパイプラインの概要

リクエストがミドルウェアパイプラインとHttpContextを通過する流れと、レスポンスが構築される仕組みを理解します。

「ASP.NET Coreパイプラインの概要」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

リクエストパイプライン

ASP.NET CoreのすべてのHTTPリクエストは、ミドルウェアパイプラインを通過します。各ミドルウェアは、リクエストを検査、変更、途中で処理を打ち切る、または次のコンポーネントへ渡すことができます。このパイプラインを理解することは、ASP.NET Coreアプリを構築するうえで基本となります。

HttpContext: リクエストの入れ物

HttpContextには、リクエストとレスポンスに関するすべての情報が含まれます。ヘッダー、Cookie、ユーザーのクレーム、接続情報、キャンセレーショントークンなどです。すべてのミドルウェアはこれを操作します。

app.Use(async (context, next) =>
{
    // Read request info
    var method  = context.Request.Method;
    var path    = context.Request.Path;
    var headers = context.Request.Headers;
    var user    = context.User.Identity?.Name;

    // Write to response
    context.Response.Headers.Append("X-Processed-By", "MyMiddleware");

    await next(context); // forward to next middleware
});

ミドルウェアの登録順序

ミドルウェアは登録された順序で実行されます。レスポンスはスタックのように逆順で処理を戻ります。順序は重要です。認証は認可より前に、ルーティングはエンドポイントのマッチングより前に実行する必要があります。

// Typical order for an ASP.NET Core app:
app.UseExceptionHandler("/error"); // outermost — catches everything
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("policy");
app.UseAuthentication();  // must be before Authorization
app.UseAuthorization();
app.UseRateLimiter();
app.UseOutputCache();
// MapHub, MapControllers, MapGet etc.
app.Run();

Use、Run、Map

ミドルウェアを追加するメソッドは3つあります。Useは次のミドルウェアを呼び出し、Runは終端となって次を呼び出さず、Mapはパスに基づいて分岐します。

// Use: passes to next
app.Use(async (ctx, next) =>
{
    Console.WriteLine("Before");
    await next(ctx);
    Console.WriteLine("After");
});

// Run: terminal — no next
app.Run(async ctx =>
    await ctx.Response.WriteAsync("Terminal"));

// Map: branch on path prefix
app.Map("/api", apiApp =>
    apiApp.Run(async ctx =>
        await ctx.Response.WriteAsync("API branch")));

リクエストとレスポンスの本文

リクエストとレスポンスの本文はストリームです。リクエスト本文は一度しか読み取れません。複数回(複数のミドルウェアなどで)読み取る必要がある場合は、リクエスト本文のバッファリングを有効にしてください。

app.Use(async (ctx, next) =>
{
    // Enable buffering so body can be read multiple times
    ctx.Request.EnableBuffering();

    using var reader = new StreamReader(
        ctx.Request.Body,
        leaveOpen: true);
    var body = await reader.ReadToEndAsync();
    ctx.Request.Body.Position = 0; // rewind for next middleware

    Console.WriteLine($"Body: {body}");
    await next(ctx);
});

パイプラインの途中終了

ミドルウェアは、レスポンスを書き込み、nextを呼び出さないことで処理を途中終了できます。認証ゲート、ヘルスチェック、メンテナンスページなどに便利です。

app.Use(async (ctx, next) =>
{
    if (ctx.Request.Path == "/maintenance")
    {
        ctx.Response.StatusCode = 503;
        await ctx.Response.WriteAsync("Service under maintenance");
        return; // short-circuit — next is NOT called
    }
    await next(ctx);
});

IMiddleware インターフェイス

DIを必要とするクラスベースのミドルウェアでは、IMiddlewareを実装してください。実装をDIに登録し、app.UseMiddleware<T>()を使用します。

public class RequestTimingMiddleware : IMiddleware
{
    private readonly ILogger<RequestTimingMiddleware> _logger;
    public RequestTimingMiddleware(ILogger<RequestTimingMiddleware> l) => _logger = l;

    public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        await next(ctx);
        _logger.LogInformation("{Method} {Path}: {Ms}ms",
            ctx.Request.Method, ctx.Request.Path, sw.ElapsedMilliseconds);
    }
}

// Register:
builder.Services.AddTransient<RequestTimingMiddleware>();
app.UseMiddleware<RequestTimingMiddleware>();

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

別の方法として、InvokeAsync(HttpContext, RequestDelegate)メソッドを持つクラスを作成できます。フレームワークは、次のデリゲートを含む依存関係をコンストラクター経由で注入します。

public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _key;

    // RequestDelegate injected by framework
    public ApiKeyMiddleware(RequestDelegate next, IConfiguration cfg)
    {
        _next = next;
        _key = cfg["ApiKey"] ?? "";
    }

    public async Task InvokeAsync(HttpContext ctx)
    {
        if (ctx.Request.Headers["X-Api-Key"] != _key)
        {
            ctx.Response.StatusCode = 401;
            return;
        }
        await _next(ctx);
    }
}

next の後でレスポンスを変更する

await next(ctx)の後にあるコードは、レスポンスの書き込みが始まった後に実行されます。nextの前でレスポンスヘッダーを追加することはできますが、その後でステータスコードや本文を変更することはできません。

app.Use(async (ctx, next) =>
{
    // Before: add response headers (safe)
    ctx.Response.OnStarting(() =>
    {
        ctx.Response.Headers.Append("X-Request-Id",
            Guid.NewGuid().ToString("N"));
        return Task.CompletedTask;
    });

    await next(ctx);

    // After: response may already be sent
    // SAFE: logging, metrics
    // UNSAFE: changing status code or writing body
    Console.WriteLine($"Response status: {ctx.Response.StatusCode}");
});

実践例: 相関 ID ミドルウェア

分散トレーシングとログ記録のため、すべてのリクエストにトレースIDを追加する本番環境向けの相関IDミドルウェアです。

public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    private const string Header = "X-Correlation-Id";

    public CorrelationIdMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext ctx)
    {
        var correlationId = ctx.Request.Headers[Header].FirstOrDefault()
            ?? Guid.NewGuid().ToString("N");

        ctx.Items["CorrelationId"] = correlationId;

        ctx.Response.OnStarting(() =>
        {
            ctx.Response.Headers.Append(Header, correlationId);
            return Task.CompletedTask;
        });

        using (Serilog.Context.LogContext.PushProperty("CorrelationId", correlationId))
            await _next(ctx);
    }
}

確認問題

ミドルウェアを追加するとき、app.Use()とapp.Run()にはどのような違いがありますか。

まとめ: ASP.NET Core パイプラインの概要

重要なポイント:

  • ミドルウェアは登録順に実行され、レスポンスは逆順に戻ります
  • Use → 次を呼び出す、Run → 終端、Map → パスに基づいて分岐
  • HttpContextにはリクエスト、レスポンス、ユーザー、キャンセレーショントークンが含まれます
  • リクエスト本文を複数回読み取るにはバッファリングを有効にします
  • IMiddlewareインターフェイスにより、DIに対応したクラスベースのミドルウェアを実装できます
  • OnStarting();でレスポンスヘッダーを追加し、nextの後でステータスを変更しないでください

よくある質問

「ASP.NET Coreパイプラインの概要」レッスンは無料ですか?

はい。「ASP.NET Coreパイプラインの概要」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「ASP.NET Coreパイプラインの概要」で何を学びますか?

リクエストがミドルウェアパイプラインとHttpContextを通過する流れと、レスポンスが構築される仕組みを理解します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「ASP.NET Coreパイプラインの概要」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ASP.NET Coreパイプラインの概要
  2. カスタムミドルウェアの作成
  3. ショートサーキットと分岐
  4. ミドルウェアの順序と組み込みミドルウェア
← C# Academyに戻る