Маршрутизация и model binding
↑ 3.3 Web API: контроллеры, Minimal API, валидация · ← Предыдущая · → Следующая
Зачем это на собесе
Уточняют: откуда берутся параметры, что такое route constraints и как работает endpoint routing.
Объяснение
Endpoint routing: UseRouting сопоставляет запрос с endpoint, последующие middleware (авторизация, CORS) видят выбранный endpoint, UseEndpoints/Map* исполняет его.
app.MapGet("/orders/{id:guid}", (Guid id) => ...);
app.MapGet("/files/{**path}", (string path) => ...); // catch-all
app.MapGet("/users/{name:alpha:minlength(3)}", ...);Ограничения: int, guid, bool, datetime, min, max, range, regex, alpha.
Model binding
| Источник | Атрибут | По умолчанию |
|---|---|---|
| Маршрут | [FromRoute] | параметры из шаблона |
| Query | [FromQuery] | простые типы |
| Тело | [FromBody] | сложные типы в [ApiController] |
| Заголовок | [FromHeader] | нет |
| Форма | [FromForm] | файлы, формы |
| DI | [FromServices] | зарегистрированные сервисы в Minimal API |
app.MapGet("/search", ([AsParameters] SearchQuery q) => ...); // группировка query в record
public record SearchQuery(string? Text, int Page = 1, [FromHeader(Name = "X-Tenant")] string? Tenant = null);System.Text.Json десериализует тело; настройки (регистр, enum, null) задаются ConfigureHttpJsonOptions.
Нюансы и подводные камни
- Тело запроса читается один раз; повторное чтение требует
EnableBuffering. - Формат даты/чисел зависит от культуры для query; используйте инвариантные форматы.
- Конфликт маршрутов даёт
AmbiguousMatchException. - Без ограничения
guid/intневалидное значение приведёт к 404 или 400 в зависимости от типа. - Регистронезависимость маршрутов включена, параметров JSON — только camelCase по умолчанию.
Практика
- Добавьте ограничения к маршрутам и проверьте ответы на неверный формат.
- Соберите query-параметры фильтра через
[AsParameters]. - Реализуйте catch-all маршрут для файлов.
Вопросы с ответами
Что такое endpoint routing?
Двухэтапная модель: выбор endpoint (
UseRouting) и его исполнение, между ними работают middleware, знающие о выбранном endpoint.
Откуда берётся значение параметра, если атрибут не указан?
Из шаблона маршрута, иначе из query для простых типов, из тела для сложных типов (в контроллерах с ApiController), из DI для зарегистрированных сервисов.
Как задать ограничение на параметр маршрута?
Через
{id:guid},{page:int:min(1)}и другие constraints.