Модели в ASP.NET Core MVC. Управление привязкой модели

Может быть такая ситуация, что свойство модели, имеющее ссылочный нам не требуется для нормальной работы действия контроллера. Однако, как мы уже знаем, если ссылочному типу в модели присваивается null, то привязчик модели завершается ошибкой и ModelState.IsValid возвращает false. Для того, чтобы приложение могло работать нормально, в этом и других случаях необходимо управление привязкой модели, которое осуществляется с использованием различных атрибутов.

Атрибуты управления привязкой модели

Атрибут BindRequired

Этот атрибут требует обязательного наличия значения для свойства модели. Например, рассмотрим такую модель:

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Author { get; set; } = string.Empty;
    public string Body { get; set; } = string.Empty;
}

для всех ссылочных типов мы используем значение по умолчанию, то есть такой запрос:

localhost:7163/home/post/1

и даже такой:

localhost:7163/home/post/

не приведет к ошибке привязчика и просто вернет «пустой» объект:

так как с точки логики привязчика — всё хорошо, все значения присвоены. Однако, с точки зрения обычной «житейской» логики, было бы неплохо, если бы статья имела хотя бы название. В этом случае мы можем применить атрибут BindRequired:

public class Post
{
    public int Id { get; set; }
    [BindRequired]
    public string Title { get; set; } = string.Empty;
    public string Author { get; set; } = string.Empty;
    public string Body { get; set; } = string.Empty;
}

в этом случае, если параметр title не будет определен в запросе, то мы получим ошибку состояния модели:

Атрибут BindNever

В противоположность атрибуту BindRequired, указывает, что свойство модели необходимо исключить из механизма привязки. Например, если мы его применим к свойству Body:

public class Post
{
    public int Id { get; set; }

    [BindRequired]
    public string Title { get; set; } = string.Empty;
    
    public string Author { get; set; } = string.Empty;
    
    [BindNever]
    public string Body { get; set; } = string.Empty;
}

то, даже если мы выполним такой запрос

localhost:7163/home/post/1?title=Hello, world&body=текст статьи

то получим следующий вывод:

Атрибут BindingBehavior

Атрибут BindingBehavior устанавливает поведение привязки с помощью одно из значений одноименного перечисления BindingBehavior:

  • Required — аналогично действию атрибута BindRequired
  • Never — аналогично действию атрибута BindNever
  • Optional — действие по умолчанию. Если значение не передается, то применяется значение по умолчанию.

Например, для свойства Body как раз может подойти применение этого атрибута:

public class Post
{
    public int Id { get; set; }
    [BindRequired]
    public string Title { get; set; } = string.Empty;
    
    public string Author { get; set; } = string.Empty;
    
    [BindingBehavior(BindingBehavior.Optional)]
    public string Body { get; set; } = string.Empty;
}

В этом случае запрос

localhost:7163/home/post/1?title=Hello, world&body=текст статьи

вернет

а запрос

localhost:7163/home/post/1?title=Hello, world

не приведет к ошибке привязки:

Атрибут Bind

Атрибут Bind позволяет установить выборочную привязку отдельных значений. Например, применим этот атрибут к параметру действия:

public IActionResult Post([Bind("Title", "Id")]Post post)
{   if (ModelState.IsValid)
      return Ok(post);
    else
        return BadRequest(ModelState);
}

а из модели уберем все действия

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string Body { get; set; }
}

в этом случае ошибка привязки будет только в том случае, если мы не присвоим значение параметру title

Атрибуты управления источниками данных

В предыдущей статье мы узнали про порядок обхода привязчиком модели различных источников для получения значений. Но следующая группа атрибутов позволяет переопределить это поведение, указав конкретный источник для поиска значений:

  • [FromHeader] данные извлекаются из заголовков запроса
  • [FromQuery] данные извлекаются из строки запроса
  • [FromRoute] данные извлекаются из значений маршрута
  • [FromForm] данные извлекаются из форм
  • [FromBody] данные извлекаются из тела запроса. Этот атрибут может применяться, когда в качестве источника данных выступает не форма и не строка запроса, а также, если метод имеет только один параметр, иначе будет сгенерировано исключение.

Например, напишем следующий метод, выделяющий из заголовков сервера значение некоторых заголовков, необходимых для дальнейшей работы:

public IActionResult Headers([FromHeader(Name = "Accept-Encoding")]string encoding,
                              [FromHeader(Name = "Accept")] string accept,
                              [FromHeader(Name = "User-Agent")] string userAgent) 
{ 
    return Ok(new{ encoding, accept, userAgent });
}

Результат работы действия:

Аналогичным образом работают и другие атрибуты управления источниками данных.

Итого

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

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии