Модели в ASP.NET Core MVC. Валидация модели

Валидация модели занимает ключевое место в разработке приложения в целом так как позволяет выявить какие-либо ошибки в модели до того как эти ошибки приведут к аварийной остановке приложения или получению некорректного результата. В ASP.NET Core MVC валидация модели базируется на общем для .NET механизме валидации, но, при этом дополняет этот механизм некоторыми другими возможностями, например, использованием атрибута Remote.

Работа со свойством ModelState

Мы уже немного работали с этим свойством, когда разбирались с механизмом привязки моделей. Здесь мы познакомимся с этим свойством более подробно. ModelState представляет объект ModelStateDictionary, в котором содержится различная информация о состоянии модели, в том числе и сведения об ошибках. Данные в  ModelStateDictionary содержатся в виде пар «ключ-значение», где ключ — это название свойства, а значение — объект типа ModelStateEntry, содержащий детальную информацию о состоянии свойства. Чтобы продемонстрировать работу со свойством ModelState, создадим новое приложение ASP.NET Core MVC и добавим в папку Models файл Person.cs со следующей моделью данных:

using System.ComponentModel.DataAnnotations;

namespace AspModelState.Models
{
    public class Person
    {
        [Required]
        public string Name { get; set; }
        [Required]
        public int Age { get; set; }
    }
}

здесь оба свойства модели содержат атрибут Required, указывающий на то, что свойства обязательно должны содержать значение. Теперь добавим тип этой модели в  представление Views/Home/Index.cshtml следующую форму и создадим в этом представлении следующую форму, используя для примера html-хэлперы:

@model Person
@using (Html.BeginForm(FormMethod.Post))
{
    @Html.LabelFor(n=>n.Name, "Имя:")
    <br />
    @Html.TextBoxFor(n=>n.Name);
    <br/>
    @Html.LabelFor(n=>n.Age, "Возраст:")
    <br />
    @Html.TextBoxFor(n=>n.Age, new{type = "number"})
    <br />
    @Html.TextBox("btn", "Отправить", new{type = "submit"})
}

Теперь перейдем к контроллеру HomeController и внесем в него следующие изменения:

[HttpGet]
public IActionResult Index()
{
    return View();
}

[HttpPost]
public IActionResult Index(Person person)
{
    if (ModelState.IsValid)
    {
        return Ok(person);
    }
    else
    {
        StringBuilder stringBuilder = new StringBuilder();
        foreach (var item in ModelState)
        {
            switch (item.Value.ValidationState)
            {
                case ModelValidationState.Unvalidated:
                    {
                        stringBuilder.Append($"Свойство {item.Key} не проверено\n");
                        break;
                    }
                case ModelValidationState.Skipped:
                    {
                        stringBuilder.Append($"Свойство {item.Key} пропущено\n");
                        break;
                    }
                case ModelValidationState.Invalid:
                    {
                        stringBuilder.Append($"Свойство {item.Key} содержит ошибки:\n");
                        foreach (var error in item.Value.Errors)
                        {
                            stringBuilder.Append($"\t{error.ErrorMessage}\n");
                        }
                        break;
                    }
                case ModelValidationState.Valid:
                    {
                        stringBuilder.Append($"Свойство {item.Key} успешно прошло проверку\n");
                        break;
                    }
            }
        }
        return BadRequest(stringBuilder.ToString());
    }
}

здесь мы установили атрибут [HttpGet] для метода Index() без параметров, указав тем самым, что это действие будет выполняться только при GET-запросах, т.е., по сути, только выводить созданную нами форму.

Также мы создали ещё один метод Index() с атрибутом [HttpPost], который будет обрабатывать POST-запрос, когда пользователь будет отправлять форму на сервер. В этом методе демонстрируется работа с различными свойствами ModelState. Так, если модель пройдет валидацию (ModelState.IsValid будет равно true), то в браузере мы увидим JSON-объект, например,

В случае, если модель проверку не пройдет, то запустится цикл по всем элементам, содержащимся в ModelState:

foreach (var item in ModelState)

Для каждого элемента item проверяется значение:

item.Value.ValidationState

то есть состояние проверки значения свойства. ValidationState может принимать следующие значения:

  • ModelValidationState.Unvalidated — свойство ещё не проверялось
  • ModelValidationState.Skipped — свойство исключено из проверки
  • ModelValidationState.Invalid — свойство содержит ошибки
  • ModelValidationState.Valid — свойство успешно прошло проверку

Если обнаруживается свойство с ошибками, то запускается цикл, который считывает все ошибки для свойства:

foreach (var error in item.Value.Errors) 
{ 
   stringBuilder.Append($"\t{error.ErrorMessage}\n"); 
}

в конце, вместе с ошибкой 400 возвращается информацию о проверке модели. В работающем приложении это будет выглядеть следующим образом:

или так (если одно из свойство пройдет проверку)

Изменение состояния модели

Вполне возможно, что при проверке модели нам может потребоваться какая-то дополнительная проверка свойств модели, которую мы не сможем осуществить, используя только штатные средства. Свойство ModelState позволяет изменить состояние модели. Например, проведем дополнительную проверку свойства Age:

 public IActionResult Index(Person person)
        {
            if (person.Age < 18)
                ModelState.AddModelError("Age", "Возраст пользователя должен быть 18+");
....
}

Здесь мы проверяем, чтобы возраст пользователя был 18+ и, если пользователь не подходит под этот параметр, то вызывается метод ModelState.AddModelError(), который добавляет для свойства Age ошибку и, следовательно, свойство ModelState.IsValid будет равно false. В итоге, если мы попробует отправить вот такие данные формы:

то, в итоге, получим следующую ошибку:

Настройка проверки модели

При необходимости, мы можем задать настройки проверки модели отличные от тех, которые задаются ASP.NET Core MVC по умолчанию. Для этого необходимо задать настройки при добавлении сервисов MVC:

builder.Services.AddControllersWithViews(options => 
{
    options.MaxModelValidationErrors = 1;//максимальное количество ошибок, после которых проверка прерывается
});

По умолчанию это свойство равно 200.

Итого

Валидация модели занимает важное место в разработке приложений. В ASP.NET Core MVC валидация модели базируется на общем механизме валидации в .NET, но, при этом, вносит в этот механизм свои дополнительные возможности, например, по изменению состояния модели через свойство ModelState.

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