ショートサーキットと分岐
MapWhen、UseWhen、終端ミドルウェアを使い、リクエスト条件に応じてパイプラインを分岐または終了させます。
「ショートサーキットと分岐」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
分岐と処理の途中終了
すべてのリクエストがミドルウェアパイプライン全体を通過する必要はありません。ASP.NET Coreには、分岐(一部のリクエストを別のパイプラインへ振り分ける)と処理の途中終了(処理を停止してすぐに返す)のための機能があります。
Map: パスによる恒久的な分岐
Mapは恒久的な分岐を作成します。プレフィックスに一致するリクエストは分岐へ入り、メインパイプラインには決して戻りません。
app.Map("/api", apiApp =>
{
apiApp.UseAuthentication();
apiApp.UseAuthorization();
apiApp.Run(async ctx =>
await ctx.Response.WriteAsync("API branch"));
});
// Requests to /api/... enter the branch above.
// Requests to /public/... skip the branch entirely.
app.Run(async ctx =>
await ctx.Response.WriteAsync("Main pipeline"));MapWhen: 述語による分岐
MapWhenは、ヘッダー、クエリパラメーター、カスタムロジックなど、任意の条件に基づいて分岐します。Mapと同様に分岐は恒久的で、メインパイプラインには再合流しません。
// Branch when a specific header is present
app.MapWhen(
ctx => ctx.Request.Headers.ContainsKey("X-Internal"),
internalApp =>
{
internalApp.UseMiddleware<InternalApiMiddleware>();
internalApp.Run(async ctx =>
await ctx.Response.WriteAsync("Internal route"));
});
// Branch on query parameter
app.MapWhen(
ctx => ctx.Request.Query.ContainsKey("legacy"),
legacyApp => legacyApp.UseMiddleware<LegacyHandlerMiddleware>());UseWhen: 再合流する条件付き分岐
UseWhenはMapWhenに似ていますが、分岐の処理が完了した後にメインパイプラインへ再合流します。これにより、パイプラインを分岐させずにミドルウェアを条件付きで追加できます。
// Log only for authenticated API calls; public routes not logged
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments("/api")
&& ctx.User.Identity?.IsAuthenticated == true,
loggedApp =>
{
loggedApp.UseMiddleware<AuditMiddleware>();
});
// All requests continue here after the branch
app.UseRouting();
app.MapControllers();Next を呼び出さないことによる処理の途中終了
どのミドルウェアでも、レスポンスを書き込み、nextを呼び出さないことで処理を途中終了できます。その時点でパイプラインが停止し、レスポンスがクライアントに返されます。
app.Use(async (ctx, next) =>
{
// IP allowlist check
var ip = ctx.Connection.RemoteIpAddress?.ToString();
var allowed = new[] { "127.0.0.1", "::1", "10.0.0.0/8" };
if (!IsAllowed(ip, allowed))
{
ctx.Response.StatusCode = 403;
await ctx.Response.WriteAsJsonAsync(
new { error = "Access denied from this IP" });
return; // short-circuit
}
await next(ctx); // proceed
});.NET 8 の ShortCircuit()
.NET 8では、MapShortCircuitとエンドポイントのShortCircuit()拡張メソッドによって、宣言的で高度に最適化された処理の途中終了パスを利用できます。
// Reject known bad paths immediately — skip entire pipeline
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
// Or on a specific endpoint:
app.MapGet("/health", () => "OK")
.ShortCircuit(); // skips auth, rate limiting, etc.
// 'Run' middleware also short-circuits:
app.Map("/old-api", old =>
old.Run(ctx =>
{
ctx.Response.StatusCode = 301;
ctx.Response.Headers.Location = "/api/v2";
return Task.CompletedTask;
}));終端ミドルウェアとエンドポイントルーティング
.NET 3より前は、app.Run()が唯一の終端オプションでした。現在はエンドポイントルーティング(MapGet、MapControllers)が推奨されています。認可、レート制限、メタデータの処理に参加できるためです。
// OLD: terminal middleware
app.Run(async ctx => {
if (ctx.Request.Path == "/ping")
await ctx.Response.WriteAsync("pong");
});
// PREFERRED: endpoint routing
app.MapGet("/ping", () => "pong")
.WithTags("Health")
.AllowAnonymous()
.RequireRateLimiting("basic");パスマッチングの注意点
Map("/api")は/apiと/api/anythingに一致します。分岐内では、一致したパスがRequest.Pathから削除され、Request.PathBaseに設定されます。
app.Map("/api", apiApp =>
{
apiApp.Use(async (ctx, next) =>
{
// Path in branch: /users/42 (prefix removed)
Console.WriteLine(ctx.Request.Path); // /users/42
Console.WriteLine(ctx.Request.PathBase); // /api
await next(ctx);
});
apiApp.MapGet("/users/{id}", (int id) => id);
});分岐パターンの組み合わせ
実際のアプリでは、Map、UseWhen、処理の途中終了を組み合わせて階層化されたパイプラインを作成します。公開ルートは軽量にし、APIルートには認証を適用し、管理者ルートには追加のチェックを適用できます。
// Public area — no auth
app.Map("/public", pub =>
{
pub.MapGet("/health", () => "OK");
pub.MapGet("/docs", () => "Documentation");
});
// API area — full auth + rate limiting
app.Map("/api", api =>
{
api.UseAuthentication();
api.UseAuthorization();
api.UseRateLimiter();
api.MapControllers();
});
// Admin area — require admin role
app.Map("/admin", admin =>
{
admin.UseAuthentication();
admin.UseAuthorization();
admin.MapControllers().RequireAuthorization("AdminPolicy");
});実践例: A/Bテストミドルウェア
A/Bテストミドルウェアは、Cookieまたはヘッダーに基づいてリクエストを異なるハンドラーへ分岐させます。エンドポイントのコードを変更する必要はありません。
app.UseWhen(
ctx => ctx.Request.Cookies.TryGetValue("ab-group", out var g) && g == "B",
betaApp =>
{
betaApp.Use(async (ctx, next) =>
{
ctx.Items["IsGroupB"] = true;
await next(ctx);
});
});
// Endpoint reads the flag:
app.MapGet("/products", (HttpContext ctx, ProductService svc) =>
{
bool isB = ctx.Items.ContainsKey("IsGroupB");
return isB ? svc.GetNewLayoutAsync() : svc.GetOldLayoutAsync();
});確認問題
MapWhenとUseWhenの主な違いは何ですか。
まとめ: 処理の途中終了と分岐
重要なポイント:
Map: パスに基づく恒久的な分岐(再合流しません)MapWhen: 述語に基づく恒久的な分岐UseWhen: メインパイプラインへ再合流する条件付き分岐- 処理の途中終了:
nextを呼び出さず、レスポンスを書き込んで返します ShortCircuit()(.NET 8): 宣言的で最適化された終端エンドポイント- 分岐を組み合わせて、公開/API/管理者向けの階層化されたパイプラインを構築します
よくある質問
「ショートサーキットと分岐」レッスンは無料ですか?
はい。「ショートサーキットと分岐」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「ショートサーキットと分岐」で何を学びますか?
MapWhen、UseWhen、終端ミドルウェアを使い、リクエスト条件に応じてパイプラインを分岐または終了させます。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「ショートサーキットと分岐」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。