В этой части мы рассмотрим вопросы валидации модели, касающиеся непосредственно ASP.NET Core.
Свойство контроллера ModelState
Если класс контроллера наследуется от класса ControllerBase
, то у него появляется такое полезное свойство как ModelState
– состояние модели, представленное классом ModelStateDictionary
. Данные в ModelStateDictionary
содержатся в виде пар «ключ-значение», где ключ — это название свойства, а значение — объект типа ModelState
, содержащий детальную информацию о состоянии свойства. Это свойство активно используется разработчиками в контроллерах, при разработке приложений с использованием MVC. Что касается приложений Web API, то, хоть мы напрямую можем и не взаимодействовать с этим свойством, однако видим результаты его использования в ответах сервера.
Дело в том, что, как мы уже убедились ранее, при использовании для контроллера атрибута [ApiController]
включается механизм автоматических откликов при возникновении ошибок с кодом статуса 400 Bad Request и сервер, используя ModelState
возвращает нам сообщение об ошибке. При желании мы можем отключить автоматический отклик сервера и воспользоваться этим свойством в своей работе.
Чтобы отключить автоматический отклик сервера на ошибки с кодом статуса HTTP 400, необходимо добавить в файл Program.cs следующую настройку:
builder.Services.AddControllers().ConfigureApiBehaviorOptions(config => { config.SuppressModelStateInvalidFilter = true; })
После применения этой настройки мы должны будем самостоятельно вручную генерировать ответы сервера, содержащие описание ошибки. Рассмотрим основные свойства класса ModelStateDictionary
Имя | Тип | Описание |
Count |
int |
Количество пар «ключ-значение» в коллекции |
IsReadOnly |
bool |
Содержит True , если коллекция доступна только для чтения |
IsValid |
bool |
Содержит False , если в коллекции содержатся ошибки валидации модели |
Item[String] |
ModelState |
Возвращает значение пары по имени её ключа |
Keys |
ICollection<String> |
Коллекция ключей |
Values |
ICollection<ModelState> |
Коллекция значений |
HasReachedMaxErrors |
bool |
Указывает было ли достигнуто максимальное количество ошибок |
ValidationState |
ModelValidationState |
Состояние валидации модели. Может принимать одно из следующих значений: Unvalidated , Invalid , Valid , Skipped |
Чтобы иметь представление какую информацию мы можем использовать в своих приложениях Web API, вернемся к нашему запросу, выполнение которого гарантированно вызовет ошибку валидации модели
@temperature = 100 @summary = "Scorching" POST {{WebApplication5_HostAddress}}/weatherforecast Content-Type: application/json { "date": "2025-03-16", "temperatureC": {{temperature}}, "temperatureF": 112, "summary": {{summary}} }
Попробуйте выполнить этот запрос при отключенном автоматическом отклике сервера, и вы увидите, что сервер вернет код статуса 200 Ok
, несмотря на то, что происходит ошибка валидации. Теперь изменим действие контроллера для добавления нового ресурса:
[HttpPost] public ActionResult Add(WeatherForecast forecast) { if (ModelState.IsValid == false) { return BadRequest(ModelState); } forecasts.Add(forecast); return Ok(); }
Здесь мы, используя свойство IsValid
, проверяем результат валидации модели. Если валидация закончилась ошибкой, то создается объект, содержащий значения свойств ModelState
, который возвращается с кодом 400 BadRequest пользователю. Если же, валидация модели прошла успешно, то, как и ранее, пользователю возвращается ответ с кодом статуса 200 Ok. Таким образом, если запрос пользователя содержит ошибку, то ответ сервера будет следующим
Здесь стоит обратить внимание на то, что сообщение об ошибке уже не соответствует RFC 7807 и, как было сказано выше, формировать ответ об ошибке придется полностью вручную.
Изменение состояния модели
Свойство ModelState
позволяет, при необходимости, добавлять собственные элементы типа ModelState
. Например, возможна такая ситуация, при которой модель успешно проходит валидацию по всем формальным признакам, однако в логике работы приложения модель использоваться не может. В этом случае мы можем изменить состояние модели. Например,
[HttpPost] public ActionResult Add(WeatherForecast forecast) { ModelState.AddModelError("Custom", "Модель не может быть использована"); if (ModelState.IsValid == false) { return BadRequest(ModelState); } forecasts.Add(forecast); return Ok(); }
В данном случае мы добавляем новую ошибку валидации модели с ключом «Custom», изменяя тем самым состояние модели. В результате, даже, если будет отправлен полностью верный запрос на добавление нового ресурса, то сервер вернет следующим ответ
Настройка проверки модели
Иногда нам не требуется, чтобы сервер возвращал сразу все возникшие ошибки валидации и привязки модели. В этом случае мы можем настроить работу приложения так, чтобы код статуса HTTP 400 присваивался ответу после определенного количества обнаруженных ошибок. Для этого мы должны настроить сервис контроллеров, например, следующим образом
builder.Services.AddControllers(config => { config.MaxModelValidationErrors = 1;});
При такой настройке мы получим ответ с кодом статуса 400 при обнаружении первой ошибки, даже в том случае, если модель будет содержать большее количество ошибок.
Итого
Автоматический отклик на ошибки с кодом 400 Bad Request в контроллерах с атрибутом [ApiController]
избавляет нас от лишней рутинной работы по формированию ответа, соответствующего RFC 7807. Однако, при желании, мы можем отключать такой отклик в приложении и формировать сообщения об ошибках самостоятельно, используя свойство контроллера ModelState
, если класс контроллера является наследником от ControllerBase
.