0Pricing
C# Academy · Урок

Группы маршрутов, параметры и проверка

Организуйте конечные точки с помощью MapGroup, привязывайте параметры маршрута, запроса и тела, а также выполняйте проверку с помощью аннотаций данных.

«Группы маршрутов, параметры и проверка» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Группы маршрутов для организации

MapGroup() (появившийся в .NET 7) позволяет объединять связанные конечные точки под общим префиксом и применять общую конфигурацию — промежуточное ПО, политики аутентификации и теги — без повторения этой настройки для каждой конечной точки.

Создание группы маршрутов

Вызовите app.MapGroup("/api/products"), а затем сопоставьте конечные точки с возвращённой группой. Префикс автоматически добавляется в начало всех маршрутов.

var products = app.MapGroup("/api/products").WithTags("Products");

products.MapGet("/",     GetAll);
products.MapGet("/{id}", GetById);
products.MapPost("/",    Create);
products.MapPut("/{id}", Update);
products.MapDelete("/{id}", Delete);
// Routes: /api/products, /api/products/{id}

Добавление аутентификации для группы

Используйте RequireAuthorization() для группы, чтобы сразу защитить все её конечные точки. Отдельные конечные точки по-прежнему могут переопределить это поведение с помощью AllowAnonymous().

var adminGroup = app.MapGroup("/admin")
    .RequireAuthorization("AdminPolicy")
    .WithTags("Admin");

adminGroup.MapGet("/users",    GetAllUsers);
adminGroup.MapDelete("/users/{id}", DeleteUser);

// This one inside the group opts out
adminGroup.MapGet("/status", () => "OK").AllowAnonymous();

Ограничения параметров маршрута

Ограничивайте параметры маршрута с помощью шаблонов типов. Маршрутизатор отклоняет запросы, которые им не соответствуют, автоматически возвращая 404.

// Only matches numeric IDs
app.MapGet("/products/{id:int}", (int id) => id);

// GUID constraint
app.MapGet("/orders/{orderId:guid}", (Guid orderId) => orderId);

// Length constraint
app.MapGet("/codes/{code:length(6)}", (string code) => code);

// Min value
app.MapGet("/page/{page:min(1)}", (int page) => page);

Связывание из разных источников

Параметры связываются с разными источниками с помощью атрибутов. По умолчанию простые типы берутся из маршрута или строки запроса, а сложные — из тела запроса.

app.MapPost("/search", (
    [FromQuery] string q,
    [FromQuery] int page,
    [FromHeader(Name = "X-Api-Version")] string version,
    [FromBody] SearchFilters filters,
    AppDbContext db) =>
{
    // q and page from query string
    // version from request header
    // filters from JSON body
    return Results.Ok();
});

Пользовательское связывание параметров с помощью TryParse

Для пользовательских типов, используемых как параметры маршрута или строки запроса, реализуйте статический метод TryParse. Платформа автоматически вызывает его для разбора строкового значения.

public record ProductFilter(string? Category, decimal? MinPrice)
{
    public static bool TryParse(string value, out ProductFilter result)
    {
        var parts = value.Split(':');
        result = new ProductFilter(
            parts.Length > 0 ? parts[0] : null,
            parts.Length > 1 && decimal.TryParse(parts[1], out var p) ? p : null);
        return true;
    }
}

// Usage: GET /products?filter=Electronics:50
app.MapGet("/products", ([FromQuery] ProductFilter filter) => filter);

Проверка с помощью атрибутов данных

Добавляйте к DTO запросов атрибуты аннотаций данных. В минимальных API используйте интерфейс IValidatableObject или фильтр проверки, чтобы запускать проверку.

using System.ComponentModel.DataAnnotations;

record CreateProductRequest
{
    [Required, MaxLength(200)]
    public string Name { get; init; } = "";

    [Range(0.01, 999999)]
    public decimal Price { get; init; }

    [Range(0, int.MaxValue)]
    public int Stock { get; init; }
}

Фильтры конечных точек для проверки

Фильтры конечных точек выполняются до или после обработчика. Используйте их для добавления проверки модели — недействительные запросы отклоняются до передачи бизнес-логике.

app.MapPost("/products", CreateProduct)
   .AddEndpointFilter(async (ctx, next) =>
   {
       var req = ctx.GetArgument<CreateProductRequest>(0);
       var errors = new List<ValidationResult>();
       if (!Validator.TryValidateObject(req,
               new ValidationContext(req), errors, true))
       {
           return Results.ValidationProblem(
               errors.ToDictionary(e => e.MemberNames.First(),
                                   e => new[] { e.ErrorMessage! }));
       }
       return await next(ctx);
   });

Интеграция с FluentValidation

Для сложных правил проверки используйте FluentValidation с пакетом SharpGrip.FluentValidation.AutoValidation.Endpoints для автоматической проверки в минимальных API.

public class CreateProductValidator : AbstractValidator<CreateProductRequest>
{
    public CreateProductValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(200);
        RuleFor(x => x.Price).GreaterThan(0);
        RuleFor(x => x.Stock).GreaterThanOrEqualTo(0);
    }
}

builder.Services.AddFluentValidationAutoValidation();
builder.Services.AddValidatorsFromAssemblyContaining<CreateProductValidator>();

Вложенные группы маршрутов

Группы маршрутов можно вкладывать друг в друга для моделирования иерархических ресурсов, например заказов, содержащих позиции.

var api = app.MapGroup("/api").RequireAuthorization();

var orders = api.MapGroup("/orders");
orders.MapGet("/", GetAllOrders);
orders.MapGet("/{id:int}", GetOrder);

// Nested: /api/orders/{orderId}/lines
var lines = orders.MapGroup("/{orderId:int}/lines");
lines.MapGet("/",        GetOrderLines);
lines.MapPost("/",       AddOrderLine);
lines.MapDelete("/{id}", RemoveOrderLine);

Практический пример: группа API с версиями

Группируйте конечные точки по версии API, чтобы поддерживать версии, работающие параллельно, без дублирования настройки аутентификации или тегов.

var v1 = app.MapGroup("/api/v1")
    .RequireAuthorization()
    .WithTags("v1");

var v2 = app.MapGroup("/api/v2")
    .RequireAuthorization()
    .WithTags("v2");

v1.MapGet("/products", GetProductsV1);
v2.MapGet("/products", GetProductsV2); // richer response

Быстрая проверка

Каково назначение MapGroup() в минимальных API?

Итоги: группы маршрутов, параметры и проверка

Основные выводы:

  • MapGroup(): общий префикс и конфигурация для нескольких конечных точек
  • Ограничения маршрутов (:int, :guid, :min) автоматически отклоняют маршруты, которым они не соответствуют
  • [FromQuery], [FromHeader], [FromBody] задают источник связывания явно
  • Реализуйте TryParse для пользовательских типов, чтобы автоматически связывать параметры маршрута и строки запроса
  • Фильтры конечных точек позволяют решать сквозные задачи, например выполнять проверку

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

Урок «Группы маршрутов, параметры и проверка» бесплатный?

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

Чему я научусь в уроке «Группы маршрутов, параметры и проверка»?

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

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

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

Сколько времени занимает урок «Группы маршрутов, параметры и проверка»?

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

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

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

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

  1. Создание первого минимального API
  2. Группы маршрутов, параметры и проверка
  3. Промежуточное ПО и фильтры в минимальных API
  4. OpenAPI, версионирование и развёртывание
← Назад к C# Academy