Что такое привязка модели (model binding) параметров в ASP.NET Core?

Ответ

Привязка модели (Model Binding) в ASP.NET Core — это процесс, в ходе которого фреймворк автоматически извлекает данные из HTTP-запроса (из строки запроса, тела, заголовков, маршрута) и преобразует их в параметры методов контроллера или Razor Page. Это избавляет разработчика от ручного парсинга сырых данных запроса.

Источники данных для привязки (в порядке приоритета по умолчанию):

  1. Из значений маршрута: {id} в шаблоне [Route("api/products/{id}")].
  2. Из строки запроса (Query String): ?page=1&sort=name.
  3. Из тела запроса (Body): Данные в формате JSON, XML, form-data.
  4. Из заголовков (Headers).
  5. Из предоставленной формы (Form fields).

Как это работает:

  1. При поступлении запроса ASP.NET Core ищет метод действия (Action) в контроллере.
  2. Для каждого параметра метода система привязки ищет совпадение по имени (или с помощью атрибутов) в источниках данных запроса.
  3. Найденные строковые значения преобразуются (парсятся) в типы параметров (int, DateTime, сложные объекты).

Практические примеры:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // Пример 1: Привязка из нескольких источников
    // GET api/products/5?details=true
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id, // Из маршрута {id}
                                    bool details) // Из query string ?details=true
    {
        // ...
    }

    // Пример 2: Привязка сложного объекта из тела запроса (JSON)
    // POST api/products
    [HttpPost]
    public IActionResult CreateProduct(Product product) // Данные автоматически десериализуются из Body
    {
        // Свойства объекта Product (Name, Price) заполнены из JSON-тела запроса
        // ...
    }

    // Пример 3: Явное указание источника с помощью атрибутов
    [HttpGet("search")]
    public IActionResult Search([FromQuery] string term, // Только из строки запроса
                                [FromHeader("X-API-Key")] string apiKey) // Только из заголовка
    {
        // ...
    }
}

public class Product
{
    public int Id { get; set; } // Может привязываться из маршрута или тела
    public string Name { get; set; } // Обычно из тела запроса
    public decimal Price { get; set; }
}

Важные аспекты:

  • [ApiController] атрибут автоматически делает вывод о том, что сложные типы привязываются из тела запроса, а простые — из строки запроса.
  • Валидация модели: После успешной привязки можно проверить данные с помощью атрибутов валидации ([Required], [Range]), вызвав ModelState.IsValid.
  • Кастомизация: Поведение привязки можно настраивать через поставщиков значений (IValueProvider) и связывателей моделей (IModelBinder).

Ответ 18+ 🔞

А, модель байндинг в ASP.NET Core! Ну это ж та штука, которая избавляет тебя от ручного выковыривания данных из запроса, как изюм из булки. Представь: приходит HTTP-запрос, а фреймворк сам, как заправский карманник, аккуратно достаёт оттуда данные и суёт их тебе прямо в параметры метода. Красота, а не жизнь!

Откуда он данные-то тянет, этот пройдоха? Да отовсюду, сука! Идёт по списку, как голодный по холодильнику:

  1. Сначала шарит по маршруту (Route): api/products/{id} — о, нашёл id!
  2. Потом рыщет в строке запроса (Query String): ?page=1&sort=name — ага, page и sort тоже забираем.
  3. Если не нашел, лезет в тело запроса (Body): Там JSON, XML или form-data валяется — разбирает и тащит.
  4. Может даже в заголовки (Headers) заглянуть.
  5. И в поля формы (Form fields), если что.

Как работает этот механизм? Да элементарно, Ватсон!

  1. Припёрся запрос — ASP.NET Core ищет, какой метод контроллера вызвать.
  2. Смотрит на параметры этого метода. Для каждого начинает искать совпадение по имени во всех этих источниках данных.
  3. Нашёл какую-то строку "123" — и думает: «Ага, тут параметр int id нужен. Щас я это "123" в циферку превращу». И превращает. Магия, блядь!

Смотри, как на практике выглядит:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // Пример 1: Привязка из нескольких мест сразу
    // Запрос: GET api/products/5?details=true
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id, // Это возьмёт из маршрута, из {id}
                                    bool details) // А это из строки запроса, ?details=true
    {
        // И уже тут у тебя не строки, а нормальные типы: id = 5, details = true
        // ...
    }

    // Пример 2: Привязка целого объекта из JSON-тела
    // Запрос: POST api/products + JSON в теле
    [HttpPost]
    public IActionResult CreateProduct(Product product) // Всё! Фреймворк сам разберёт JSON и создаст объект Product
    {
        // product.Name и product.Price уже заполнены. Ничего парсить не надо!
        // ...
    }

    // Пример 3: Когда надо жёстко указать, откуда брать. Используем атрибуты.
    [HttpGet("search")]
    public IActionResult Search([FromQuery] string term, // Чётко говорим: только из строки запроса, иначе нахуй!
                                [FromHeader("X-API-Key")] string apiKey) // А это только из заголовка с таким именем
    {
        // ...
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Важные фишки, которые надо помнить:

  • Атрибут [ApiController] — это такой умный дед. Он автоматом предполагает, что сложные объекты (типа Product) лезут из тела, а простые параметры (типа int, string) — из строки запроса. Очень удобно, не надо постоянно атрибуты лепить.
  • Валидация — после того как всё привязали, можно проверить, а правильные ли данные прислал этот распиздяй-клиент. ModelState.IsValid в помощь, а на свойствах — атрибуты вроде [Required] или [Range].
  • Если совсем припёрло и стандартное поведение не подходит — можно настроить свою логику привязки через IValueProvider или IModelBinder. Но это уже для глубоких извращенцев, там дохуя работы.

Короче, модель байндинг — это одна из тех фич ASP.NET Core, которая делает рутину за тебя. Сидишь такой, пьёшь кофе, а данные сами в метод приплывают. Главное — правильно имена параметров назвать или атрибуты расставить, а дальше фреймворк всё сделает. Ёпта, живи да радуйся!