단락 처리와 분기
요청 조건에 따라 파이프라인을 분기하거나 종료하도록 MapWhen, UseWhen, 종단 미들웨어를 사용합니다.
단락 처리와 분기은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
분기와 조기 종료
모든 요청이 전체 미들웨어 파이프라인을 통과해야 하는 것은 아닙니다. ASP.NET Core는 분기(요청의 일부를 다른 파이프라인으로 라우팅)와 조기 종료(처리를 중단하고 즉시 반환)를 위한 도구를 제공합니다.
Map: 경로에 따른 영구 분기
Map은 영구적인 분기를 만듭니다. 접두사와 일치하는 요청은 분기로 들어가며 NEVER 주 파이프라인으로 돌아오지 않습니다.
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를 호출하지 않음으로써 조기에 종료할 수 있습니다. 해당 지점에서 파이프라인이 중지되고 응답이 클라이언트로 반환됩니다.
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, 조기 종료를 결합해 계층화된 파이프라인을 만듭니다. 공개 경로는 가볍게 처리하고, 애플리케이션 프로그래밍 인터페이스 경로에는 인증을 적용하며, 관리자 경로에는 추가 검사를 적용합니다.
// 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 테스트 미들웨어는 엔드포인트 코드를 수정하지 않고 쿠키나 헤더에 따라 요청을 서로 다른 처리기로 분기합니다.
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): 선언적이고 최적화된 종료 엔드포인트- 분기를 결합해 계층화된 파이프라인을 구축합니다: 공개 / 애플리케이션 프로그래밍 인터페이스 / 관리자
자주 묻는 질문
“단락 처리와 분기” 강의는 무료인가요?
네 — “단락 처리와 분기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“단락 처리와 분기”에서 뭘 배우나요?
요청 조건에 따라 파이프라인을 분기하거나 종료하도록 MapWhen, UseWhen, 종단 미들웨어를 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
C# Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“단락 처리와 분기” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.