C# Academy · Урок

Досрочное завершение и ветвление

Используйте MapWhen, UseWhen и завершающее промежуточное ПО, чтобы создавать ветви или завершать конвейер в зависимости от условий запроса.

Урок 3 из 412 шагов

«Досрочное завершение и ветвление» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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
});

ShortCircuit() в .NET 8

В .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-тестирования направляет запросы к разным обработчикам на основе файла 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): декларативные и оптимизированные конечные точки, завершающие обработку
  • Сочетайте ветвление для создания многоуровневых конвейеров: общедоступные маршруты / маршруты программного интерфейса / административные маршруты
Можно начать бесплатно

Изучай C# с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
93
Уроки
346

Часто задаваемые вопросы

Урок «Досрочное завершение и ветвление» бесплатный?

Да — полный текст урока «Досрочное завершение и ветвление» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Досрочное завершение и ветвление»?

Используйте MapWhen, UseWhen и завершающее промежуточное ПО, чтобы создавать ветви или завершать конвейер в зависимости от условий запроса. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Досрочное завершение и ветвление»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Обзор конвейера ASP.NET Core
  2. Написание собственного промежуточного ПО
  3. Досрочное завершение и ветвление
  4. Порядок промежуточного ПО и встроенные компоненты
← Назад к C# Academy