Ответ
Маршрутизация в ASP.NET Core настраивается несколькими способами, от конвенциональных до полностью кастомных.
1. Конвенциональная маршрутизация (Conventional Routing)
Настраивается глобально в Program.cs или Startup.Configure. Это стиль, знакомый по ASP.NET MVC.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// Дополнительные маршруты
app.MapControllerRoute(
name: "blog",
pattern: "blog/{*slug}",
defaults: new { controller = "Blog", action = "ReadPost" });
2. Атрибутная маршрутизация (Attribute Routing) Наиболее гибкий и предпочтительный способ. Маршруты задаются напрямую над контроллерами и действиями.
[Route("api/[controller]")] // Базовый маршрут: /api/products
[ApiController]
public class ProductsController : ControllerBase
{
[HttpGet] // GET /api/products
public IActionResult GetAll() { ... }
[HttpGet("{id:int}")] // GET /api/products/5
public IActionResult GetById(int id) { ... }
[HttpPost("special")] // POST /api/products/special
public IActionResult PostSpecial([FromBody] Product product) { ... }
}
3. Маршрутизация в минимальных API (Minimal APIs)
Использует методы расширения MapGet, MapPost и т.д.
app.MapGet("/products", () => "Список продуктов");
app.MapGet("/products/{id:int}", (int id) => $"Продукт {id}");
app.MapPost("/products", (Product product) => Results.Created($"/products/{product.Id}", product));
4. Динамическая/кастомная маршрутизация
Можно создать собственный IRouteConstraint для валидации параметров или реализовать DynamicRouteValueTransformer для динамического преобразования маршрутов на лету (например, для мультитенантности или CMS).
// Пользовательское ограничение
public class CustomConstraint : IRouteConstraint { ... }
// Использование в атрибуте
[HttpGet("{id:customConstraint}")]
public IActionResult Get(string id) { ... }
5. Маршрутизация по областям (Areas) Организует контроллеры и представления в отдельные группы для больших приложений.
[Area("Admin")]
[Route("Admin/[controller]/[action]")]
public class UsersController : Controller { ... }
Ключевые принципы:
- Используйте атрибутную маршрутизацию для API и сложных схем.
- Порядок регистрации маршрутов важен — более специфичные должны регистрироваться раньше общих.
- Всегда добавляйте ограничения типов (
{id:int}) для параметров маршрута, где это возможно.
Ответ 18+ 🔞
Давай разберём эту маршрутизацию в ASP.NET Core, а то некоторые думают, что это какая-то высшая математика, блядь. На самом деле всё проще, чем кажется, если не заморачиваться.
1. Конвенциональная маршрутизация (Старая школа)
Это как дедовский метод, из времён, когда динозавры по земле ходили. Настраиваешь один раз в Program.cs и потом пляшешь от этого. Выглядит как магия, потому что маршруты прикручиваются сами по шаблону.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"); // Классика жанра: /Home/Index/5
Смысл простой: взял контроллер Home, действие Index, а id — если есть. Если нет — иди нахуй, без id обойдёшься. Можно ещё дополнительные маршруты навесить, например, для блога, чтобы всё, что идёт после /blog/, ловилось одним действием. Удобно, но гибкости — как у трактора, блядь.
2. Атрибутная маршрутизация (Так сейчас все делают) Вот это уже серьёзно. Ты прямо на контроллере и методах пишешь, куда какой запрос идёт. Никакой магии, всё прозрачно, как слёзы ребёнка. Предпочтительный способ, особенно для API.
[Route("api/[controller]")] // Базовый путь: /api/products
[ApiController]
public class ProductsController : ControllerBase
{
[HttpGet] // GET /api/products
public IActionResult GetAll() { ... }
[HttpGet("{id:int}")] // GET /api/products/5. int — это важно, чтобы какой-нибудь мудак строку не подсунул.
public IActionResult GetById(int id) { ... }
[HttpPost("special")] // POST /api/products/special
public IActionResult PostSpecial([FromBody] Product product) { ... }
}
Всё наглядно, ебать. Хочешь — параметры ограничивай, хочешь — вложенные пути делай. Красота.
3. Маршрутизация в минимальных API (Для тех, кто любит по-быстрому) Новомодная фича, когда тебе нахуй не нужны контроллеры, а хочется всё в одном файле описать. Выглядит лаконично, но в больших проектах можно ебнуться, если не организовать код.
app.MapGet("/products", () => "Список продуктов"); // Проще некуда
app.MapGet("/products/{id:int}", (int id) => $"Продукт {id}"); // С параметром
app.MapPost("/products", (Product product) => Results.Created($"/products/{product.Id}", product)); // И даже пост
Идеально для микросервисов или когда делаешь прототип побыстрее. Но если размахнёшься, есть риск получить спагетти-код, который потом разматывать будешь неделю.
4. Динамическая/кастомная маршрутизация (Для извращенцев) Когда стандартных возможностей мало и хочется прикрутить какую-нибудь хуйню, например, маршруты, которые меняются в зависимости от клиента или времени суток. Тут уже надо свои классы писать.
// Сделал свой IRouteConstraint, чтобы проверять параметры по своим правилам.
public class CustomConstraint : IRouteConstraint { ... }
// И используешь
[HttpGet("{id:customConstraint}")]
public IActionResult Get(string id) { ... }
Мощный инструмент, но если накосячишь — отладка превратится в ад, блядь. Пользоваться с умом.
5. Маршрутизация по областям (Areas)
Для больших монолитных приложений, где всё свалено в кучу. Areas позволяют логически сгруппировать функционал, типа Admin, Client, Reports.
[Area("Admin")] // Говорим, что это админка
[Route("Admin/[controller]/[action]")] // И все пути будут начинаться с /Admin/
public class UsersController : Controller { ... }
Полезно, когда контроллеров становится овердохуища и нужно хоть как-то поддерживать порядок.
Ключевые принципы, которые надо запомнить:
- Для API бери атрибутную маршрутизацию — меньше геморроя, больше контроля.
- Порядок регистрации маршрутов — важен как никогда. Специфичные пути (типа
blog/special-article) регистрируй раньше общих (типаblog/{slug}), а то общий шаблон всё перехватит и будешь думать, почему твой экшен не вызывается, ёпта. - Всегда ограничивай тип параметра в маршруте, где это возможно (
{id:int},{guid:regex(...)}). Иначе получишь в метод строку, когда ждал число, и потом будешь искать, где же ошибка, блядь. - Минимальные API — это быстро и просто, но для большого проекта лучше использовать контроллеры, а то потом поддерживать этот цирк будет некому.
Вот и вся наука. Ничего сложного, главное — начать использовать, а там уже набьёшь руку.