次の方法で共有


ASP.NET Core のミドルウェア

これは、この記事の最新バージョンではありません。 現在のリリースについては、 この記事の .NET 10 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、 この記事の .NET 10 バージョンを参照してください。

ミドルウェアとは、要求と応答を処理するために、アプリのパイプラインに組み込まれたソフトウェアです。 各ミドルウェア:

  • パイプライン内の次のミドルウェアに要求を渡すかどうかを選択します。
  • パイプライン内の次のミドルウェアの前後に作業を実行できます。

要求デリゲートは、要求パイプラインの構築に使用されます。 要求デリゲートは、各 HTTP 要求を処理します。

要求デリゲートは、RunMapUse の各拡張メソッドを使って構成されます。 個々の要求デリゲートは、匿名メソッド (インライン ミドルウェアと呼ばれます) としてインラインで指定することも、再利用可能なクラスで定義することもできます。 これらのインライン匿名メソッドまたは再利用可能なクラスは、 ミドルウェア または ミドルウェア コンポーネントと呼ばれます。 要求パイプライン内の各ミドルウェアは、パイプラインで次のミドルウェアを呼び出すか、パイプラインをショートサーキットする役割を担います。 ショートサーキットしたミドルウェアは "ターミナル ミドルウェア" と呼ばれます。これにより、さらなるミドルウェアが要求を処理しなくなるためです。

ASP.NET Core と ASP.NET 4.x の要求パイプラインと追加のミドルウェア サンプルの違いの詳細については、「 HTTP モジュールを ASP.NET Core ミドルウェアに移行する」を参照してください。

アプリの種類別ミドルウェアの役割

サーバー側の Blazor、 Razor Pages、MVC はミドルウェアを使用してサーバー上のブラウザー要求を処理します。 この記事のガイダンスは、これらの種類のアプリに適用されます。

スタンドアロン Blazor WebAssembly アプリはクライアント上で完全に実行され、ミドルウェア パイプラインで要求を処理しません。 この記事のガイダンスは、スタンドアロン Blazor WebAssembly アプリには適用されません。

ミドルウェアのコード分析

アプリ コードの品質を検査する ASP.NET Core のコンパイラ プラットフォーム アナライザーの詳細については、「 ASP.NET Core アプリでのコード分析」を参照してください。

WebApplication を使用してミドルウェア パイプラインを作成する

ASP.NET Core 要求パイプラインは、順番に呼び出される一連の要求デリゲートで構成されています。 次の図は、その概念を示しています。 実行プロセスのスレッドは黒い矢印に従います。

要求の到着、3 つのミドルウェアによる処理、アプリからの応答の送信を示す要求処理パターン。3 番目のミドルウェアが要求を処理した後、要求は前の 2 つのミドルウェアを逆の順序で通過して、それぞれの next() ステートメントの後の追加処理が行われた後、クライアントへの応答としてアプリを終了します。

各デリゲートは、次のデリゲートの前と後に操作を実行できます。 例外処理デリゲートは、パイプラインの後のステージで発生する例外をキャッチできるように、パイプラインの早い段階で呼び出される必要があります。

このセクションのコード例を使用してローカルで実験するには、ASP.NET Core 空のプロジェクト テンプレートを使用して ASP.NET Core アプリを作成します。 .NET CLI を使用している場合、テンプレートの短い名前は web (dotnet new web)。

最も単純な ASP.NET Core アプリ呼び出し Run 、要求パイプラインなしで要求を処理する匿名関数要求デリゲートとして 1 つのターミナル ミドルウェアを設定します。

次に例を示します。

  • RunExtensions.Runの呼び出しは、すべての要求で呼び出され、応答に "Hello world!" を書き込みます。
  • コード ブロックの最後に WebApplication.Run を呼び出すと、アプリが実行され、ホストがシャットダウンするまで呼び出し元のスレッドがブロックされます。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

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

app.Run();

ブラウザーの起動時 URL でアプリにアクセスするときの応答:

Hello world!

複数の要求デリゲートを Use と一緒にチェーンします。 next パラメーターは、パイプラインの次のデリゲートを表します 通常、 next デリゲートの前後にアクションを実行できます。

その具体的な例を次に示します:

  • 2 つの Use 呼び出し。各呼び出しがコンソールに書き込まれます。
    • 応答 (context.ResponseHttpResponse) に書き込むことができる作業を実行できる場所。
    • next パラメーターの呼び出し後に応答に書き込まない作業を実行できる場所。
  • 応答に "RunExtensions.Run" を書き込むHello world!の呼び出しを含むターミナル要求デリゲート。
  • 最後の Use 呼び出し。これは、 Run ターミナル要求デリゲートに従うため実行されません。
  • コード ブロックの末尾に WebApplication.Run を呼び出してアプリを実行し、ホストがシャットダウンするまで呼び出し元のスレッドをブロックします。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    Console.WriteLine("Work that can write to the response. (1)");
    await next.Invoke(context);
    Console.WriteLine("Work that doesn't write to the response. (1)");
});

app.Use(async (context, next) =>
{
    Console.WriteLine("Work that can write to the response. (2)");
    await next.Invoke(context);
    Console.WriteLine("Work that doesn't write to the response. (2)");
});

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

app.Use(async (context, next) =>
{
    Console.WriteLine("This statement isn't reached. (3)");
    await next.Invoke(context);
    Console.WriteLine("This statement isn't reached. (3)");
});

app.Run();

アプリが実行されたときのアプリのコンソール ウィンドウで、次の手順を実行します。

応答に書き込むことができる作業。 (1)
応答に書き込むことができる作業。 (2)
応答に書き込まれない作業。 (2)
応答に書き込まれないタスク。 (1)

要求パイプラインをショートサーキットすることは、多くの場合、不要な作業を回避するため望ましいことです。 たとえば、静的ファイル ミドルウェア は、静的ファイルに対する要求を処理し、残りのパイプラインを中断させることで、ターミナル ミドルウェア として機能できます。 ミドルウェアは、ターミナルミドルウェアの前にパイプラインに追加されており、それでもnext.Invokeステートメントの後にコードを処理します。 パイプラインを終了することが目標であるためにnext.Invokeを呼び出す予定がない場合は、Run拡張メソッドを呼び出す代わりにUseを使用します。

応答がクライアントに送信される間または後に next.Invoke を呼び出さないでください。 HttpResponseが開始されると、変更によって例外が発生します。 たとえば、ヘッダーまたはレスポンスのステータスコードを設定すると、レスポンスが開始した後に例外が発生しますnextを呼び出した後に応答本文に書き込むには、次の場合があります。

  • 指定された応答のコンテンツ長 (ヘッダー値Content-Length ) よりも多くのバイトを応答に書き込むなど、プロトコル違反が発生します。
  • CSS ファイルに HTML フッターを書き込むことで、ファイル形式を破損させる。

応答が開始されたかどうかを確認するには、 HasStartedの値を確認します。

詳しくは、「ルーティング後のミドルウェアのショートサーキット」を参照してください。

Run デリゲート

Run デリゲートは、next パラメーターを受け取りません。 最初の Run デリゲートは、常にパイプラインを終了します。 Run は規則でもあり、一部のミドルウェアでは、パイプラインの最後に実行される Run メソッドが公開される場合があります。

最初のUse デリゲートの後のRunまたはRunデリゲートは呼び出されません。

ミドルウェア パイプラインを分岐する

Map 拡張機能は、要求処理パイプラインを分岐する規則として使用されます。 Map は、指定された要求パスの一致に基づいて、要求パイプラインを分岐します。 要求パスが指定されたパスで開始する場合、分岐が実行されます。

次の例では、HandleMap1要求に対して/map1が呼び出され、HandleMap2要求に対して/map2が呼び出されます。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMap1);
app.Map("/map2", HandleMap2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate!");
});

app.Run();

private static void HandleMap1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map 1");
    });
}

private static void HandleMap2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map 2");
    });
}

次の表に、上記のコードを使用した要求と応答を示します。

要求 応答
/ Hello from the non-Map delegate.
/map1 Map 1
/map2 Map 2
/map3 Hello from the non-Map delegate.

Map を使用すると、一致したパス セグメントが HttpRequest.Path から削除され、要求ごとに HttpRequest.PathBase に追加されます。

Map は、一度に複数のセグメントと一致する可能性があります。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/segment1", HandleMultipleSegments);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate.");
});

app.Run();

private static void HandleMultipleSegments(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Processing '/map1/segment1'");
    });
}

次の表に、上記のコードを使用した要求と応答を示します。

要求 応答
/ Hello from the non-Map delegate.
/map1/segment1 Processing '/map1/segment1'

Map は入れ子をサポートしています。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Processing '/level1/level2a'");
        });
    });
    level1App.Map("/level2b", level2BApp => {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Processing '/level1/level2b'");
        });
    });
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate!");
});

app.Run();

次の表に、上記のコードを使用した要求と応答を示します。

要求 応答
/ Hello from the non-Map delegate.
/level1/level2a Processing '/level1/level2a'
/level1/level2b Processing '/level1/level2b'

MapWhen は、指定された述語の結果に基づいて、要求パイプラインを分岐します。 Func<HttpContext, bool> という型の任意の述語を使って、要求をパイプラインの新しい分岐にマップできます。 次の例では、述語を使用して、"branch" という名前のクエリ文字列変数が存在することを検出します。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate.");
});

app.Run();

private static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = '{branchVer}'");
    });
}

次の表に、上記のコードを使用した要求と応答を示します。

要求 応答
/ Hello from the non-Map delegate.
/?branch=main Branch used = 'main'

UseWhen は、指定された述語の結果に基づいて要求パイプラインを分岐できます。 MapWhenとは異なり、ターミナル ミドルウェアが含まれていない場合、ブランチはメイン パイプラインに再び参加します。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer.ToString());

        Console.WriteLine("Work that can write to the response.");
        await next.Invoke(context);
        Console.WriteLine("Work that doesn't write to the response.");
    });
}

前の例では、すべての要求に対して "Hello from the non-Map delegate." の応答が書き込まれます。 要求に "branch" という名前のクエリ文字列変数が含まれている場合、メイン パイプラインが再参加する前にその値がログに記録されます。

IApplicationBuilder を使用してミドルウェア パイプラインを作成する

ASP.NET Core 要求パイプラインは、順番に呼び出される一連の要求デリゲートで構成されています。 次の図は、その概念を示しています。 実行プロセスのスレッドは黒い矢印に従います。

要求の到着、3 つのミドルウェアによる処理、アプリからの応答の送信を示す要求処理パターン。3 番目のミドルウェアが要求を処理した後、要求は前の 2 つのミドルウェアを逆の順序で通過して、それぞれの next() ステートメントの後の追加処理が行われた後、クライアントへの応答としてアプリを終了します。

各デリゲートは、次のデリゲートの前と後に操作を実行できます。 例外処理デリゲートは、パイプラインの後のステージで発生する例外をキャッチできるように、パイプラインの早い段階で呼び出される必要があります。

考えられる最も簡単な ASP.NET Core アプリは、1 つの要求デリゲートを設定してすべての要求を処理するものです。 この場合、実際の要求パイプラインは含まれません。 代わりに、すべての HTTP 要求に対応して単一の匿名関数が呼び出されます。

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, World!");
        });
    }
}

複数の要求デリゲートを Use と一緒にチェーンします。 next パラメーターは、パイプラインの次のデリゲートを表します next パラメーターを "呼び出さない" ことで、パイプラインをショートさせることができます。 次の例で示すように、通常は、次のデリゲートの前と後の両方でアクションを実行できます。

app.Use(async (context, next) =>
{
    // Do work that doesn't write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

デリゲートが次のデリゲートに要求を渡さない場合、これは "要求パイプラインの短絡" と呼ばれます。 不要な処理を回避するために、ショートさせることが望ましい場合がよくあります。 たとえば、静的ファイル ミドルウェア は、静的ファイルに対する要求を処理し、残りのパイプラインを中断させることで、ターミナル ミドルウェア として機能できます。 後続の処理を終了させるミドルウェアの前にパイプラインに追加されたミドルウェアでは、その next.Invoke ステートメントの後も引き続きコードが処理されます。 ただし、既に送信された応答に対する書き込みの試行については、次の警告を参照してください。

警告

応答がクライアントに送信された後に、next.Invoke を呼び出さないでください。 応答が開始した後で HttpResponse を変更すると、例外がスローされます。 たとえば、ヘッダーや状態コードを設定すると、例外が発生しますnext を呼び出した後で応答本文に書き込むと、次のようになります。

  • プロトコル違反が発生する可能性があります。 たとえば、示されている Content-Length より多くを書き込んだ場合。
  • 本文の形式が破損する可能性があります。 たとえば、CSS ファイルに HTML フッターを書き込んだ場合。

HasStarted は、ヘッダーが送信されたかどうかや本文が書き込まれたかどうかを示すために役立つヒントです。

Run デリゲートでは、next パラメーターは受け取られません。 最初の Run デリゲートが常に終点となり、パイプラインが終了されます。 Run は規則です。 一部のミドルウェア コンポーネントでは、パイプラインの最後に実行される Run[Middleware] メソッドが公開されることがあります。

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

前の例では、Run デリゲートによって応答に "Hello from 2nd delegate." が書き込まれ、その後、パイプラインが終了となります。 別の Use または Run デリゲートが Run デリゲートの後に追加される場合、そのデリゲートは呼び出されません。

ミドルウェア パイプラインを分岐する

Map 拡張メソッドは、パイプラインを分岐する規則として使われます。 Map は、指定された要求パスの一致に基づいて、要求パイプラインを分岐します。 要求パスが指定されたパスで開始する場合、分岐が実行されます。

public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

次の表は、前のコードを使用した http://localhost:1234 からの要求および応答を示しています。

要求 応答
localhost:1234 マップ以外のデリゲートから Hello。
localhost:1234/map1 地図テスト1
localhost:1234/map2 地図テスト2
localhost:1234/map3 マップ以外のデリゲートから Hello。

Map を使用すると、一致したパス セグメントが HttpRequest.Path から削除され、要求ごとに HttpRequest.PathBase に追加されます。

Map は入れ子をサポートします。次にその例を示します。

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map では、次のように一度に複数のセグメントを照合できます。

public class Startup
{
    private static void HandleMultiSeg(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map multiple segments.");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1/seg1", HandleMultiSeg);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

MapWhen は、指定された述語の結果に基づいて、要求パイプラインを分岐します。 Func<HttpContext, bool> という型の任意の述語を使って、要求をパイプラインの新しい分岐にマップできます。 次の例では、クエリ文字列変数 branch の存在を検出するために述語が使用されます。

public class Startup
{
    private static void HandleBranch(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            var branchVer = context.Request.Query["branch"];
            await context.Response.WriteAsync($"Branch used = {branchVer}");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
                               HandleBranch);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

次の表は、前のコードを使用した http://localhost:1234 からの要求および応答を示しています。

要求 応答
localhost:1234 マップ以外のデリゲートから Hello。
localhost:1234/?branch=main 使用されたブランチ = メイン

また UseWhen では、指定された述語の結果に基づいて、要求パイプラインが分岐されます。 MapWhen とは異なり、この分岐は、ショートしたり、ターミナル ミドルウェアが含まれたりしなければ、メイン パイプラインに再参加します。

public class Startup
{
    private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.Use(async (context, next) =>
        {
            var branchVer = context.Request.Query["branch"];
            logger.LogInformation("Branch used = {branchVer}", branchVer.ToString());

            // Do work that doesn't write to the Response.
            await next();
            // Do other work that doesn't write to the Response.
        });
    }

    public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
                               appBuilder => HandleBranchAndRejoin(appBuilder, logger));

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from main pipeline.");
        });
    }
}

上記の例では、すべての要求に対して "Hello from main pipeline." の応答が書き込まれます。 要求にクエリ文字列変数 branch が含まれる場合、メイン パイプラインの再参加前にその値がログに記録されます。

ミドルウェアの順序

ミドルウェアがアプリの Program ファイルに表示される順序によって、応答の逆の順序で要求でミドルウェアが呼び出される順序が定義されます。

ミドルウェアの順序と、要求処理シナリオ用のカスタム ミドルウェアを追加する機能を完全に制御できます。ミドルウェアの順序は、セキュリティ、パフォーマンス、および機能にとって重要である可能性があることに留意してください。

次の例は、一般的なアプリ シナリオのミドルウェアの順序を示しています。 各ミドルウェア拡張メソッドは、WebApplicationBuilder名前空間を介してMicrosoft.AspNetCore.Builderで公開されます。

  1. 例外/エラー処理
    • Development環境でアプリを実行する場合:
      • 開発者例外ページ ミドルウェア (UseDeveloperExceptionPage) によりアプリの実行時エラーが報告されます。
      • データベース エラー ページ ミドルウェア (UseDatabaseErrorPage) によりデータベースの実行時エラーが報告されます。
    • Production環境でアプリを実行する場合:
      • 例外ハンドラー ミドルウェア (UseExceptionHandler) によって、後続のミドルウェアによってスローされた例外がキャッチされます。
      • HTTP Strict Transport Security プロトコル (HSTS) ミドルウェア (UseHsts) により Strict-Transport-Security ヘッダーが追加されます。
  2. HTTPS リダイレクト ミドルウェア (UseHttpsRedirection) により、HTTP 要求が HTTPS にリダイレクトされます。
  3. 静的ファイル ミドルウェア (必要に応じて、UseStaticFiles) は静的ファイルを返し、後続の要求処理を短絡します。
  4. Cookie ポリシー ミドルウェア (UseCookiePolicy) は、アプリを EU 一般データ保護規則 (GDPR) に準拠しています。
  5. ルーティング ミドルウェア (UseRouting) により、要求がルーティングされます。
  6. 認証ミドルウェア (UseAuthentication) により、ユーザーがセキュリティで保護されたリソースにアクセスする前に、ユーザーの認証が試行されます。
  7. 承認ミドルウェア (UseAuthorization) により、ユーザーがセキュリティで保護されたリソースにアクセスすることが承認されます。
  8. 偽造防止ミドルウェア (UseAntiforgery) は、UseAntiforgeryUseAuthenticationの呼び出しの後に配置する必要があるパイプライン UseAuthorizationに偽造防止ミドルウェアを追加します。
  9. セッション ミドルウェア (Razor ページと MVC のみ、 UseSession) はセッション状態を確立し、維持します。 アプリでセッション状態が使用されている場合は、 Cookie ポリシー ミドルウェアの後、およびページ/MVC ミドルウェア Razor 前にセッション ミドルウェアを呼び出します。
  10. エンドポイント ルーティング ミドルウェア
  • MapRazorComponents Razorコンポーネント エンドポイントを要求パイプラインに追加します。
  • MapRazorPagesリクエストパイプラインにRazor Pages エンドポイントを追加します。
  • MapControllerRoute コントローラー エンドポイントを要求パイプラインに追加します。

一般的な Blazor Web App ミドルウェア パイプライン:

app.UseWebAssemblyDebugging(); // Development environment with client-side rendering
app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity

app.UseExceptionHandler("/Error", createScopeForErrors: true); // Non-Development environment
app.UseHsts(); // Non-Development environment with HTTPS protocol

app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);

app.UseHttpsRedirection(); // With HTTPS protocol

app.UseAntiforgery();

app.MapStaticAssets();

app.MapRazorComponents<App>(); // With additional extension methods for render modes

app.MapAdditionalIdentityEndpoints(); // With ASP.NET Core Identity

app.Run();

一般的な Razor Pages/MVC ミドルウェア パイプライン:

app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity

app.UseExceptionHandler("/Error"); // Non-Development environment
app.UseHsts(); // Non-Development environment with HTTPS protocol

app.UseHttpsRedirection(); // With HTTPS protocol

// app.UseCookiePolicy();
app.UseRouting(); // If not called, runs at the beginning of the pipeline by default
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

// app.UseAuthentication(); // Called internally for ASP.NET Core Identity
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapStaticAssets();

app.MapControllerRoute(...); // For MVC controllers

app.MapRazorPages(); // For Razor Pages pages

app.MapControllers(); // With authentication in a Razor Pages app

app.Run();

上のコードでは以下の操作が行われます。

  • CORS ミドルウェア (UseCors)、認証ミドルウェア (UseAuthentication)、および承認ミドルウェア (UseAuthorization) は、次の順序で表示する必要があります。
  • CORS ミドルウェア (UseCors) は、応答キャッシュ ミドルウェア (UseResponseCaching) の前に表示して、キャッシュされた応答を含むすべての要求に CORS ヘッダーを追加する必要があります。 詳細については、「UseCORS が UseResponseCaching (dotnet/aspnetcore #23218) の前に来る必要があるか不明です」を参照してください。
  • 要求ローカライズ ミドルウェア (UseRequestLocalization) は、要求カルチャ (静的ファイル ミドルウェア (UseStaticFiles) など) をチェックするミドルウェアの前に表示する必要があります。
  • レート制限ミドルウェア (UseRateLimiter) は、レート制限エンドポイント固有の API を使用する場合、ルーティング ミドルウェア (UseRouting) の後に呼び出す必要があります。 たとえば、 [EnableRateLimiting] 属性 を使用する場合は、ルーティング ミドルウェアの後にレート制限ミドルウェアを呼び出す必要があります。 グローバル リミッタのみを呼び出す場合、レート制限ミドルウェアはルーティング ミドルウェアの前に呼び出すことができます。

シナリオによっては、ミドルウェアの順序が異なる場合があります。 たとえば、キャッシュと圧縮の順序は、アプリの仕様によって異なります。 次の順序では、圧縮された応答をキャッシュすることで CPU 使用率が低下する可能性がありますが、アプリでは Gzip や Brotli などの異なる圧縮アルゴリズムを使用して、リソースの複数の表現がキャッシュされる可能性があります。

app.UseResponseCaching();
app.UseResponseCompression();

通常、静的資産はパイプラインの早い段階で提供されるため、アプリは要求処理をショートサーキットしてパフォーマンスを向上させることができます。

認証は、認証されていない要求をバイパスすることはありません。 認証ミドルウェアは要求を認証しますが、承認は、フレームワークがRazor内のBlazor Web App コンポーネント、Razor Pages アプリ内のページ、または MVC アプリのコントローラーとアクションを選択した後に行われます。

次の図は、ASP.NET Core MVC と Razor Pages アプリの完全な要求処理パイプラインを示しています。 一般的なアプリでどのように既存のミドルウェアが順序付けされ、どこにカスタム ミドルウェアが追加されるかを確認できます。 シナリオでの必要性に応じて、既存のミドルウェアの順序を変更したり、新しいカスタム ミドルウェアを挿入したりする方法については、完全に制御できます。

ASP.NET Core のミドルウェア パイプライン

上記の図のエンドポイント ミドルウェアでは、対応するアプリの種類 (MVC または Razor Pages) のフィルター パイプラインが実行されます。

前の図でルーティング ミドルウェアの次には、静的ファイルが示されています。 これは、app.UseRouting を明示的に呼び出し、プロジェクト テンプレートが実装する順序です。 app.UseRouting を呼び出さない場合、既定でルーティング ミドルウェアがパイプラインの先頭で実行されます。 詳細については、ルーティングに関するページを参照してください。

Program.cs ファイルでミドルウェア コンポーネントを追加する順序は、要求でミドルウェア コンポーネントが呼び出される順序および応答での逆の順序を定義します。 この順序は、セキュリティ、パフォーマンス、および機能にとって重要です。

次の Program.cs で強調表示されているコードは、一般的な推奨される順序でセキュリティ関連のミドルウェア コンポーネントを追加します。

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

上のコードでは以下の操作が行われます。

  • 個人のユーザー アカウントを使用して新しい Web アプリを作成するときに追加されないミドルウェアは、コメント アウトされています。
  • すべてのミドルウェアが厳密にこの順序で配置されるわけではありませんが、多くの場合はそのように配置されます。 例:
    • UseCorsUseAuthentication、および UseAuthorization は、示されている順序で配置する必要があります。
    • 現時点では、UseCorsUseResponseCaching の前にある必要があります。 この要件については、GitHub issue dotnet/aspnetcore #23218 に関するページで説明されています。
    • UseRequestLocalization は、要求のカルチャをチェックする可能性があるすべてのミドルウェア (たとえば、app.UseStaticFiles()) の前に配置する必要があります。
    • レート制限エンドポイント固有の API を使う場合は、UseRateLimiter の後に UseRouting を呼び出す必要があります。 たとえば、[EnableRateLimiting] 属性を使う場合は、UseRateLimiter の後に UseRouting を呼び出す必要があります。 グローバル リミッターのみを呼び出す場合は、UseRateLimiter の前に UseRouting を呼び出すことができます。

シナリオによっては、ミドルウェアの順序が異なる場合があります。 たとえば、シナリオによって異なるキャッシュと圧縮の順序には、有効な順序は複数あります。 次に例を示します。

app.UseResponseCaching();
app.UseResponseCompression();

上記のコードでは、圧縮された応答をキャッシュして CPU の使用を減らすことができますが、Gzip や Brotli などの異なる圧縮アルゴリズムを使用してリソースの表現が複数キャッシュされてしまう場合があります。

次の順序では、圧縮された静的ファイルをキャッシュできるように、静的ファイルが結合されます。

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

次の Program.cs コードにより、共通アプリ シナリオのためのミドルウェア コンポーネントが追加されます。

  1. 例外/エラー処理
    • Development環境でアプリを実行する場合:
      • 開発者例外ページ ミドルウェア (UseDeveloperExceptionPage) によりアプリの実行時エラーが報告されます。
      • データベース エラー ページ ミドルウェア (UseDatabaseErrorPage) によりデータベースの実行時エラーが報告されます。
    • Production環境でアプリを実行する場合:
      • 例外ハンドラー ミドルウェア (UseExceptionHandler) によって、後続のミドルウェアによってスローされた例外がキャッチされます。
      • HTTP Strict Transport Security プロトコル (HSTS) ミドルウェア (UseHsts) により Strict-Transport-Security ヘッダーが追加されます。
  2. HTTPS リダイレクト ミドルウェア (UseHttpsRedirection) により、HTTP 要求が HTTPS にリダイレクトされます。
  3. 静的ファイル ミドルウェア (UseStaticFiles) によって静的ファイルが返され、さらなる要求の処理がスキップされます。
  4. Cookie ポリシー ミドルウェア (UseCookiePolicy) により、アプリを EU の一般データ保護規制 (GDPR) に準拠させます。
  5. ルーティング ミドルウェア (UseRouting) により、要求がルーティングされます。
  6. 認証ミドルウェア (UseAuthentication) により、ユーザーがセキュリティで保護されたリソースにアクセスする前に、ユーザーの認証が試行されます。
  7. 承認ミドルウェア (UseAuthorization) により、ユーザーがセキュリティで保護されたリソースにアクセスすることが承認されます。
  8. セッション ミドルウェア (UseSession) により、セッション状態が確立され保持されます。 アプリでセッション状態が使用されている場合は、Cookie ポリシー ミドルウェアの後、MVC ミドルウェアの前に、セッション ミドルウェアを呼び出します。
  9. エンドポイント ルーティング ミドルウェア (UseEndpoints を含む MapRazorPages) により、Razor Pages エンドポイントが要求パイプラインに追加されます。
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

前のコード例では、各ミドルウェアの拡張メソッドが WebApplicationBuilder 名前空間を通じて Microsoft.AspNetCore.Builder で公開されています。

パイプラインに追加された最初のミドルウェア コンポーネントは UseExceptionHandler です。 そのため、例外ハンドラー ミドルウェアでは、以降の呼び出しで発生するすべての例外がキャッチされます。

静的ファイル ミドルウェアは、パイプラインの初期段階で呼び出され、要求を処理して残りのコンポーネントを介さずにスキップすることができます。 静的ファイル ミドルウェアでは、承認チェックは提供されませんwwwroot の下にあるものも含め、この静的ファイル ミドルウェアによって提供されるすべてのファイルは、一般に公開されます。 静的ファイルをセキュリティで保護する方法については、「ASP.NET Core の静的ファイル」を参照してください。

要求が静的ファイル ミドルウェアによって処理されない場合、要求は認証を実行する認証ミドルウェア (UseAuthentication) に渡されます。 認証は、認証されていない要求をバイパスすることはありません。 認証ミドルウェアは要求を認証しますが、承認 (および却下) は、MVC が特定の Razor ページまたは MVC コントローラーとアクションを選んだ後でのみ行われます。

次の例は、静的ファイルの要求が応答圧縮ミドルウェアの前に静的ファイル ミドルウェアによって処理される、ミドルウェアの順序を示します。 静的ファイルは、このミドルウェアの順序では圧縮されません。 Razor Pages の応答は圧縮できます。

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

次の図は、ASP.NET Core MVC と Razor Pages アプリの完全な要求処理パイプラインを示しています。 一般的なアプリでどのように既存のミドルウェアが順序付けされ、どこにカスタム ミドルウェアが追加されるかを確認できます。 シナリオでの必要性に応じて、既存のミドルウェアの順序を変更したり、新しいカスタム ミドルウェアを挿入したりする方法については、完全に制御できます。

ASP.NET Core のミドルウェア パイプライン

上記の図のエンドポイント ミドルウェアでは、対応するアプリの種類 (MVC または Razor Pages) のフィルター パイプラインが実行されます。

前の図でルーティング ミドルウェアの次には、静的ファイルが示されています。 これは、app.UseRouting を明示的に呼び出し、プロジェクト テンプレートが実装する順序です。 app.UseRouting を呼び出さない場合、既定でルーティング ミドルウェアがパイプラインの先頭で実行されます。 詳細については、ルーティングに関するページを参照してください。

Program.cs ファイルでミドルウェア コンポーネントを追加する順序は、要求でミドルウェア コンポーネントが呼び出される順序および応答での逆の順序を定義します。 この順序は、セキュリティ、パフォーマンス、および機能にとって重要です。

次の Program.cs で強調表示されているコードは、一般的な推奨される順序でセキュリティ関連のミドルウェア コンポーネントを追加します。

using IndividualAccountsExample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

上のコードでは以下の操作が行われます。

  • 個人のユーザー アカウントを使用して新しい Web アプリを作成するときに追加されないミドルウェアは、コメント アウトされています。
  • すべてのミドルウェアが厳密にこの順序で配置されるわけではありませんが、多くの場合はそのように配置されます。 例:
    • UseCorsUseAuthentication、および UseAuthorization は、示されている順序で配置する必要があります。
    • 現時点では、UseCorsUseResponseCaching の前にある必要があります。 この要件については、GitHub issue dotnet/aspnetcore #23218 に関するページで説明されています。
    • UseRequestLocalization は、要求のカルチャをチェックする可能性があるすべてのミドルウェア (たとえば、app.UseMvcWithDefaultRoute()) の前に配置する必要があります。

シナリオによっては、ミドルウェアの順序が異なる場合があります。 たとえば、シナリオによって異なるキャッシュと圧縮の順序には、有効な順序は複数あります。 次に例を示します。

app.UseResponseCaching();
app.UseResponseCompression();

上記のコードでは、圧縮された応答をキャッシュして CPU の使用を減らすことができますが、Gzip や Brotli などの異なる圧縮アルゴリズムを使用してリソースの表現が複数キャッシュされてしまう場合があります。

次の順序では、圧縮された静的ファイルをキャッシュできるように、静的ファイルが結合されます。

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

次の Program.cs コードにより、共通アプリ シナリオのためのミドルウェア コンポーネントが追加されます。

  1. 例外/エラー処理
    • Development環境でアプリを実行する場合:
      • 開発者例外ページ ミドルウェア (UseDeveloperExceptionPage) によりアプリの実行時エラーが報告されます。
      • データベース エラー ページ ミドルウェア (UseDatabaseErrorPage) によりデータベースの実行時エラーが報告されます。
    • Production環境でアプリを実行する場合:
      • 例外ハンドラー ミドルウェア (UseExceptionHandler) によって、後続のミドルウェアによってスローされた例外がキャッチされます。
      • HTTP Strict Transport Security プロトコル (HSTS) ミドルウェア (UseHsts) により Strict-Transport-Security ヘッダーが追加されます。
  2. HTTPS リダイレクト ミドルウェア (UseHttpsRedirection) により、HTTP 要求が HTTPS にリダイレクトされます。
  3. 静的ファイル ミドルウェア (UseStaticFiles) によって静的ファイルが返され、さらなる要求の処理がスキップされます。
  4. Cookie ポリシー ミドルウェア (UseCookiePolicy) により、アプリを EU の一般データ保護規制 (GDPR) に準拠させます。
  5. ルーティング ミドルウェア (UseRouting) により、要求がルーティングされます。
  6. 認証ミドルウェア (UseAuthentication) により、ユーザーがセキュリティで保護されたリソースにアクセスする前に、ユーザーの認証が試行されます。
  7. 承認ミドルウェア (UseAuthorization) により、ユーザーがセキュリティで保護されたリソースにアクセスすることが承認されます。
  8. セッション ミドルウェア (UseSession) により、セッション状態が確立され保持されます。 アプリでセッション状態が使用されている場合は、Cookie ポリシー ミドルウェアの後、MVC ミドルウェアの前に、セッション ミドルウェアを呼び出します。
  9. エンドポイント ルーティング ミドルウェア (UseEndpoints を含む MapRazorPages) により、Razor Pages エンドポイントが要求パイプラインに追加されます。
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

前のコード例では、各ミドルウェアの拡張メソッドが WebApplicationBuilder 名前空間を通じて Microsoft.AspNetCore.Builder で公開されています。

パイプラインに追加された最初のミドルウェア コンポーネントは UseExceptionHandler です。 そのため、例外ハンドラー ミドルウェアでは、以降の呼び出しで発生するすべての例外がキャッチされます。

静的ファイル ミドルウェアは、パイプラインの初期段階で呼び出され、要求を処理して残りのコンポーネントを介さずにスキップすることができます。 静的ファイル ミドルウェアでは、承認チェックは提供されませんwwwroot の下にあるものも含め、この静的ファイル ミドルウェアによって提供されるすべてのファイルは、一般に公開されます。 静的ファイルをセキュリティで保護する方法については、「ASP.NET Core の静的ファイル」を参照してください。

要求が静的ファイル ミドルウェアによって処理されない場合、要求は認証を実行する認証ミドルウェア (UseAuthentication) に渡されます。 認証は、認証されていない要求をバイパスすることはありません。 認証ミドルウェアは要求を認証しますが、承認 (および却下) は、MVC が特定の Razor ページまたは MVC コントローラーとアクションを選んだ後でのみ行われます。

次の例は、静的ファイルの要求が応答圧縮ミドルウェアの前に静的ファイル ミドルウェアによって処理される、ミドルウェアの順序を示します。 静的ファイルは、このミドルウェアの順序では圧縮されません。 Razor Pages の応答は圧縮できます。

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

次の図は、ASP.NET Core MVC と Razor Pages アプリの完全な要求処理パイプラインを示しています。 一般的なアプリでどのように既存のミドルウェアが順序付けされ、どこにカスタム ミドルウェアが追加されるかを確認できます。 シナリオでの必要性に応じて、既存のミドルウェアの順序を変更したり、新しいカスタム ミドルウェアを挿入したりする方法については、完全に制御できます。

ASP.NET Core のミドルウェア パイプライン

上記の図のエンドポイント ミドルウェアでは、対応するアプリの種類 (MVC または Razor Pages) のフィルター パイプラインが実行されます。

Startup.Configure メソッドでミドルウェア コンポーネントを追加する順序は、要求でミドルウェア コンポーネントが呼び出される順序および応答での逆の順序を定義します。 この順序は、セキュリティ、パフォーマンス、および機能にとって重要です。

次の Startup.Configure メソッドでは、セキュリティ関連のミドルウェア コンポーネントが、一般的な推奨される順序で追加されています。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    // app.UseCookiePolicy();

    app.UseRouting();
    // app.UseRequestLocalization();
    // app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();
    // app.UseSession();
    // app.UseResponseCompression();
    // app.UseResponseCaching();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

上のコードでは以下の操作が行われます。

  • 個人のユーザー アカウントを使用して新しい Web アプリを作成するときに追加されないミドルウェアは、コメント アウトされています。
  • すべてのミドルウェアが厳密にこの順序で配置されるわけではありませんが、多くの場合はそのように配置されます。 例:
    • UseCorsUseAuthentication、および UseAuthorization は、示されている順序で配置する必要があります。
    • 現時点では、UseCors のバグが原因で UseResponseCaching の前に配置する必要があります。
    • UseRequestLocalization は、要求のカルチャをチェックする可能性があるすべてのミドルウェア (たとえば、app.UseMvcWithDefaultRoute()) の前に配置する必要があります。

シナリオによっては、ミドルウェアの順序が異なる場合があります。 たとえば、キャッシュと圧縮の順序はシナリオ固有のものであり、複数の有効な順序があります。 次に例を示します。

app.UseResponseCaching();
app.UseResponseCompression();

上記のコードでは、圧縮された応答をキャッシュすることによって CPU を節約できますが、Gzip や Brotli などの異なる圧縮アルゴリズムを使用してリソースの複数の表現をキャッシュすることができます。

次の順序では、圧縮された静的ファイルをキャッシュできるように、静的ファイルが結合されます。

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

次の Startup.Configure メソッドにより、共通アプリ シナリオのためのミドルウェア コンポーネントが追加されます。

  1. 例外/エラー処理
    • Development環境でアプリを実行する場合:
      • 開発者例外ページ ミドルウェア (UseDeveloperExceptionPage) によりアプリの実行時エラーが報告されます。
      • データベース エラー ページ ミドルウェアによりデータベースの実行時エラーが報告されます。
    • Production環境でアプリを実行する場合:
      • 例外ハンドラー ミドルウェア (UseExceptionHandler) によって、後続のミドルウェアによってスローされた例外がキャッチされます。
      • HTTP Strict Transport Security プロトコル (HSTS) ミドルウェア (UseHsts) により Strict-Transport-Security ヘッダーが追加されます。
  2. HTTPS リダイレクト ミドルウェア (UseHttpsRedirection) により、HTTP 要求が HTTPS にリダイレクトされます。
  3. 静的ファイル ミドルウェア (UseStaticFiles) によって静的ファイルが返され、さらなる要求の処理がスキップされます。
  4. Cookie ポリシー ミドルウェア (UseCookiePolicy) により、アプリを EU の一般データ保護規制 (GDPR) に準拠させます。
  5. ルーティング ミドルウェア (UseRouting) により、要求がルーティングされます。
  6. 認証ミドルウェア (UseAuthentication) により、ユーザーがセキュリティで保護されたリソースにアクセスする前に、ユーザーの認証が試行されます。
  7. 承認ミドルウェア (UseAuthorization) により、ユーザーがセキュリティで保護されたリソースにアクセスすることが承認されます。
  8. セッション ミドルウェア (UseSession) により、セッション状態が確立され保持されます。 アプリでセッション状態が使用されている場合は、Cookie ポリシー ミドルウェアの後、MVC ミドルウェアの前に、セッション ミドルウェアを呼び出します。
  9. エンドポイント ルーティング ミドルウェア (UseEndpoints を含む MapRazorPages) により、Razor Pages エンドポイントが要求パイプラインに追加されます。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

前のコード例では、各ミドルウェアの拡張メソッドが IApplicationBuilder 名前空間を通じて Microsoft.AspNetCore.Builder で公開されています。

パイプラインに追加された最初のミドルウェア コンポーネントは UseExceptionHandler です。 そのため、例外ハンドラー ミドルウェアでは、以降の呼び出しで発生するすべての例外がキャッチされます。

静的ファイル ミドルウェアは、パイプラインの初期段階で呼び出され、要求を処理して残りのコンポーネントを介さずにスキップすることができます。 静的ファイル ミドルウェアでは、承認チェックは提供されませんwwwroot の下にあるものも含め、この静的ファイル ミドルウェアによって提供されるすべてのファイルは、一般に公開されます。 静的ファイルをセキュリティで保護する方法については、「ASP.NET Core の静的ファイル」を参照してください。

要求が静的ファイル ミドルウェアによって処理されない場合、要求は認証を実行する認証ミドルウェア (UseAuthentication) に渡されます。 認証は、認証されていない要求をバイパスすることはありません。 認証ミドルウェアは要求を認証しますが、承認 (および却下) は、MVC が特定の Razor ページまたは MVC コントローラーとアクションを選んだ後でのみ行われます。

次の例は、静的ファイルの要求が応答圧縮ミドルウェアの前に静的ファイル ミドルウェアによって処理される、ミドルウェアの順序を示します。 静的ファイルは、このミドルウェアの順序では圧縮されません。 Razor Pages の応答は圧縮できます。

public void Configure(IApplicationBuilder app)
{
    // Static files aren't compressed by Static File Middleware.
    app.UseStaticFiles();

    app.UseRouting();

    app.UseResponseCompression();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

シングルページ アプリケーション (SPA) の場合、通常はミドルウェア パイプラインの最後に SPA ミドルウェア UseSpaStaticFiles を配置します。 SPA ミドルウェアは最後に来ます。

  • 対応する要求に最初にその他のミドルウェアが応答するため。
  • サーバー アプリが認識しないすべてのルートでクライアント側ルーティングを使用したSPAを実行できるようにするため。

SPA の詳細については、ReactAngular プロジェクト テンプレートのガイドを参照してください。

シングル ページ アプリケーションの詳細については、ReactAngular プロジェクト テンプレートのガイドを参照してください。

UseCorsUseStaticFilesの順序

UseCorsUseStaticFilesの順序付けの詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

Forwarded Headers Middleware の順序

他のミドルウェアの前に Forwarded Headers Middleware を実行して、転送されたヘッダー情報に依存するミドルウェアがヘッダー値を処理に使用できることを確認します。 診断とエラー処理ミドルウェアの後に転送されたヘッダー ミドルウェアを実行するには、「 転送されたヘッダー ミドルウェアの順序」を参照してください。

組み込みミドルウェア

ASP.NET Core の最新リリースには、次のミドルウェアが付属しています。 UI スタック列は、ミドルウェアが使用される一般的な UI スタックを示します [すべて、Blazor Web App (BWA)、Razor Pages and MVC (RP/MVC)]。 "順番" 列には、要求を処理するパイプライン内のミドルウェアの配置と、ミドルウェアが要求処理を終了する条件に関するメモが記載されています。 ミドルウェアが要求を処理するパイプラインをショートサーキットし、下流のさらなるミドルウェアによる要求の処理を回避する場合、これは "ターミナル ミドルウェア" と呼ばれます。 ショートサーキットの詳細については、「WebApplicationを使用したミドルウェア パイプラインの作成」セクションを参照してください。

ミドルウェア 説明 UI スタック 並べ替え
偽造防止 要求フォージェリ防止のサポートを提供します。 All 認証と承認を行った後、エンドポイントに到達する前に。
認証 認証のサポートを提供します。 All HttpContext.Userが必要になる前に。 OAuth コールバック用の端末。
承認 承認のサポートを提供します。 All 認証ミドルウェアの直後。
Cookie ポリシー 個人情報の保存に関してユーザーからの同意を追跡し、cookie や secure など、SameSite フィールドの最小要件を適用します。 All Cookie を発行するミドルウェアの前。 次に例を示します。 認証、セッション、MVC (TempData)
CORS クロス オリジン リソース共有を構成します。 All CORS を使用するミドルウェアの前。 UseCors は、 UseResponseCachingの前に移動する必要があります。 詳細については、「UseCORS が UseResponseCaching (dotnet/aspnetcore #23218) の前に来る必要があるか不明です」を参照してください。
開発者例外ページ Development環境でのみ使用することを目的としたエラー情報を含むページを生成します。 All エラーを生成するミドルウェアの前。 プロジェクト テンプレートは、環境が Developmentされるときに、このミドルウェアをパイプラインの最初のミドルウェアとして自動的に登録します。
診断 開発者の例外ページ、例外処理、状態コード ページ、および新しいアプリの既定の Web ページを提供する複数の独立したミドルウェア。 All エラーを生成するミドルウェアの前。 例外処理のためのターミナルや、新しいアプリ用の既定のWebページを提供するためのターミナル。
転送されるヘッダー プロキシされたヘッダーを現在の要求に転送します。 All 更新されたフィールドを使用するミドルウェアの前。 例: スキーム、ホスト、クライアント IP、メソッド。
ヘルスチェック ASP.NET Core アプリとその依存関係の正常性を、データベースの可用性などで確認します。 All 要求が正常性チェックのエンドポイントと一致した場合の終端。
ヘッダーの伝達 HTTP ヘッダーを受信要求から送信 HTTP クライアント要求に伝達します。
All
HTTP のログ HTTP 要求と応答をログに記録します。 All ミドルウェア パイプラインの先頭。
HTTP メソッドのオーバーライド メソッドをオーバーライドする受信 POST 要求を許可します。 All 更新されたメソッドを使用するミドルウェアの前。
HTTPS リダイレクト すべての HTTP 要求を HTTPS にリダイレクトします。 All URL を使用するミドルウェアの前。
HTTP Strict Transport Security (HSTS) 特殊な応答ヘッダーを追加するセキュリティ拡張機能のミドルウェア。 All 応答が送信される前と、要求を変更するミドルウェアの後。 次に例を示します。 転送されるヘッダー、URL リライト。
MVC MVC または Razor Pages で要求を処理します。 RP/MVC 要求がルートと一致した場合の終端。
OWIN OWIN ベースのアプリ、サーバー、およびミドルウェアと相互運用します。 RP/MVC OWIN ミドルウェアが要求を完全に処理した場合の終端。
出力キャッシュ 構成に基づく応答のキャッシュのサポートを提供します。 RP/MVC キャッシュを必要とするミドルウェアの前。 UseRoutingUseCors は、 UseOutputCacheの前に来る必要があります。
応答キャッシュ 応答のキャッシュのサポートを提供します。 これには、クライアントの参加が機能する必要があります。 サーバーを完全に制御するには、出力キャッシュを使用します。 RP/MVC キャッシュを必要とするミドルウェアの前。 UseCors の前に UseResponseCaching を追加する必要があります。 通常、ブラウザーはキャッシュを妨げる要求ヘッダーを設定するため、応答キャッシュは、 Razor ページなどの UI アプリには役立たない。 UI アプリには出力キャッシュが有益です。
圧縮解除を要求する 圧縮解除の要求をサポートします。 All 要求本文を読み取るミドルウェアの前。
応答圧縮 応答の圧縮のサポートを提供します。 All 圧縮を必要とするミドルウェアの前。
要求のローカライズ ローカライズのサポートを提供します。 All ローカライズに対応するミドルウェアの前。 RouteDataRequestCultureProvider を使用する場合は、ルーティング ミドルウェアの後に配置する必要があり ます。
要求タイムアウト グローバルおよびエンドポイントごとに、要求のタイムアウトを構成するサポートを提供します。 All UseRequestTimeoutsUseExceptionHandlerUseDeveloperExceptionPageUseRouting の後に来る必要があります。
エンドポイント ルーティング 要求のルートを定義および制約します。 All 一致するルートの終端。
スパ シングル ページ アプリケーション (SPA) の既定のページを返すことによって、ミドルウェア チェーン内のこのポイントからのすべての要求を処理します。 All パイプラインの後半に表示されるため、MVC アクションなど、静的ファイルを提供するための他のミドルウェアが優先されます。
セッション ユーザー セッションの管理のサポートを提供します。 RP/MVC セッションを必要とするミドルウェアの前。
静的ファイル 静的ファイルとディレクトリ参照に対応するサポートを提供します。 All 要求がファイルと一致した場合の終端。
URL 書き換え URL の書き換えと要求のリダイレクトのサポートを提供します。 All URL を使用するミドルウェアの前。
W3C ログ W3C 拡張ログ ファイル形式でサーバー アクセス ログを生成します。 All ミドルウェア パイプラインの先頭。
Blazor WebAssembly デバッグ Chromium 開発者ツールでクライアント側レンダリング (CSR) を採用するBlazor Web Appのデバッグを行う。 BWA ミドルウェア パイプラインの先頭。
WebSocket WebSocket プロトコルを有効にします。 All WebSocket 要求を受け入れる必要があるミドルウェアの前に配置します。

追加のリソース