Ответ
Выбор действия (Action) — это процесс маршрутизации запросов (Routing), который сопоставляет входящий HTTP-запрос с исполняемым методом контроллера. Механизм работает на основе соглашений или, чаще, атрибутов маршрутизации.
Ключевые критерии сопоставления:
- HTTP-метод: Атрибуты
[HttpGet],[HttpPost],[HttpPut]и т.д. - Шаблон маршрута (Route Template): Определяется в
[Route("...")]на контроллере или действии. - Имя контроллера и действия (при использовании соглашений).
- Параметры запроса (из сегментов пути, строки запроса или тела).
Пример 1: Маршрутизация на основе атрибутов (рекомендуемый подход)
[ApiController]
[Route("api/[controller]")] // Базовый путь: /api/products
public class ProductsController : ControllerBase
{
// GET /api/products
[HttpGet]
public IActionResult GetAll() { /* ... */ }
// GET /api/products/5
[HttpGet("{id:int}")] // Ограничение типа параметра
public IActionResult GetById(int id) { /* ... */ }
// POST /api/products/search
[HttpPost("search")]
public IActionResult Search([FromBody] SearchFilter filter) { /* ... */ }
}
Пример 2: Соглашения (Convention-based routing) в Program.cs
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// Запрос /Products/Details/3 будет направлен в ProductsController.Details(3)
Процесс выбора:
- Промежуточное ПО маршрутизации (
app.UseRouting()) анализирует URL запроса. - Создается набор кандидатов — действий, чьи шаблоны и HTTP-методы совпадают.
- Из кандидатов выбирается наиболее специфичное действие (с большим количеством сегментов и ограничений).
- Если найдено несколько одинаково специфичных действий, возникает
AmbiguousActionException. - После выбора действия выполняется привязка модели (Model Binding) для параметров.
Ответ 18+ 🔞
Давай разберём эту вашу маршрутизацию, а то как будто в трёх соснах пиздеца ищешь. Сидит запрос, бедолага, в интернетах болтается, и ему надо понять, в какой метод контроллера ткнуть носом. Весь этот цирк называется выбор действия (Action Selection).
Если по-простому, то это такой умный дворник, который смотрит на URL, смотрит на тип запроса (GET, POST и прочая хуйня) и решает, какую функцию в твоём коде вызвать. Работает он либо по старым дедовским соглашениям, либо по атрибутам — что, честно говоря, в разы удобнее и понятнее.
На что этот дворник-маршрутизатор смотрит, чтобы не облажаться:
- HTTP-метод: Это типа
[HttpGet],[HttpPost],[HttpPut]. Если запрос пришёл POST-ом, а метод помечен только[HttpGet]— нихуя не выйдет, мимо. - Шаблон пути (Route Template): Прописывается в
[Route("...")]. Это как адрес на конверте. "Иди на такой-то путь, сынок". - Имя контроллера и действия: Если используешь старые соглашения, а не атрибуты.
- Параметры запроса: Вытаскиваются из пути, из строки запроса или прямо из тела.
Пример 1: Нормальный, человеческий способ через атрибуты (делай так!)
[ApiController]
[Route("api/[controller]")] // Значит, базовый путь будет /api/products
public class ProductsController : ControllerBase
{
// GET /api/products
[HttpGet]
public IActionResult GetAll() { /* ... */ }
// GET /api/products/5
[HttpGet("{id:int}")] // Смотри, какая красота! Ограничение, что id только int. Не int — 404, пошёл нахуй.
public IActionResult GetById(int id) { /* ... */ }
// POST /api/products/search
[HttpPost("search")]
public IActionResult Search([FromBody] SearchFilter filter) { /* ... */ }
}
Пример 2: Старый, дедовский способ через соглашения (Program.cs)
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// Расшифровываю: запрос /Products/Details/3 полетит прямиком в ProductsController.Details(3)
А теперь, как это всё работает под капотом, чтоб ты понимал:
- Запрос приплывает, и промежуточное ПО маршрутизации (
app.UseRouting()) начинает его разглядывать, как идиот иконку. - Оно собирает всех "кандидатов" — те методы контроллеров, у которых шаблон пути и HTTP-метод хоть как-то подходят.
- Из этой толпы выбирается самый придирчивый и уточнённый кандидат. У кого в шаблоне больше сегментов и ограничений — тот и красавчик.
- Если вдруг нашлось два метода, которые одинаково хороши, фреймворк ахуевает и кидает
AmbiguousActionException. Сам виноват, распиздяй, сделай правила чёткими. - Ну а когда действие выбрано, начинается магия привязки модели (Model Binding) — подтягиваются параметры из запроса в аргументы метода.
Вот и вся магия. Не так страшен чёрт, как его малюют. Главное — атрибуты используй и шаблоны пиши понятно, а то сам потом в своей же логике запутаешься.