Валидация в Web API

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 29.10.2015

В Web API, как и в MVC, большое значение имеет валидация данных. Однако в Web API она имеет свои особенности.

В первую очередь состояние обработки запроса на сервере мы можем контроллировать с помощью статусных кодов:

  • 200: статус Ok. Указывает на удачное выполнение запроса

  • 201: статус Created. Указывает на успешное создание объекта, как правило, используется в запросах POST

  • 204: статус NoContent - запрос прошел успешно, например, после удаления

  • 400: статус BadRequest - ошибка при выполнении запроса

  • 401: статус Unathorized - пользователь не авторизован

  • 403: статус Forbidden - доступ запрещен

  • 404: статус NotFound - ресурс не найден

Отправляя определенный статусный код, мы уже даем клиенту знать о характере возникшей ошибки или статусе запросе.

Но мы не ограничены статусными кодами и, как и в MVC, можем использовать для валидации объект ModelState.

Допустим, мы работаем со следующей моделью:

public class Book
{
    public int Id { get; set; }
	
    [Required(ErrorMessage="Укажите название книги")]
    public string Name { get; set; }
    
	[Range(1800, 2000, ErrorMessage = "Год должен быть в промежутке от 1800 до 2000")]
    [Required(ErrorMessage = "Укажите год издания книги")]
    public int Year { get; set; }
}

В Web API применяются все те же атрибуты валидации, что и в ASP.NET MVC. Общая схема валидации в контроллере Web API, например, при обработке запроса POST, будет выглядеть следующим образом:

public class ValuesController : ApiController
{
    // POST api/values
    public IHttpActionResult Post(Book book)
    {
        // отправка статусного кода 400
        if (book == null)
            return BadRequest();

        // обработка частных случаев валидации
        if (book.Year == 1984)
            ModelState.AddModelError("book.Year", "Год не должен быть равен 1984");

        if (book.Name == "Война и мир")
        {
            ModelState.AddModelError("book.Name", "Недопустимое название для книги");
            ModelState.AddModelError("book.Name", "Название не должно начинаться с заглавной буквы");
        }
            
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

		// если запрос без ошибок
        return Ok();
    }
}

С помощью объекта ModelState здесь валидируется полученная модель book. Но кроме проверки свойства ModelState.IsValid мы также можем добавить и еще дополнительные проверки. Например:

if (book.Year == 1984)
    ModelState.AddModelError("book.Year", "Год не должен быть равен 1984");

Для добавления дополнительной ошибки используется метод ModelState.AddModelError, первый параметр которого - ключ ошибки, а второй - сообщение об ошибке. В качестве ключа мы можем использовать любое значение, но по умолчанию система сохраняет все ошибки свойств модели по ключу "переменная_модели.Название_свойства". В нашем случае модель преставлена переменной book, поэтому все ошибки, связанные со свойством Year, сохраняются по ключу book.Year. Причем по одному ключу мы можем указать множество ошибок.

Все ошибки валидаци сохраняются в объекте ModelState, который передается в метод BadRequest и, таким образом, отправляется клиенту вместе с ошибкой 400.

Теперь рассмотрим, как мы можем получить эти ошибки на стороне клиента. Пусть у нас будет следующее представление:

@{
    Layout = null;
}
<!doctype html>
<html>
<head>
    <title>Валидация</title>
    <meta charset="utf-8" />
</head>
<body>
<div>
    <input type="text" name="name" id="nameText" required />
    <input type="number" name="year" max="2000" min="1800" id="yearText" required />
    <input type="submit" value="Отправить" id="submit" />
</div>
<div id="errors" style="color:red;"></div>
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript">
$(function () {
    $("#submit").click(function (event) {
        event.preventDefault();
        AddBook();
    });

    function AddBook() {
        // получаем значения для добавляемой книги
        var book = {
            Name: $('#nameText').val(),
            Year: $('#yearText').val()
        };

        $.ajax({
            url: '/api/values/',
            type: 'POST',
            data: JSON.stringify(book),
            contentType: "application/json;charset=utf-8",
            success: function (data, status) { $('#errors').empty(); },
            error: function (jxqr, error, status) {
                // парсинг json-объекта
				var response = jQuery.parseJSON(jxqr.responseText);
                $('#errors').empty();
                $('#errors').append("<h2>" + response['Message'] + "</h2>");
				// добавляем ошибки свойства Year
                if (response['ModelState']['book.Name']){

                    $.each(response['ModelState']['book.Name'], function (index, item) {
						$('#errors').append("<p>" + item + "</p>");
                    });
                }
                // добавляем ошибки свойства Name
                if (response['ModelState']['book.Year']) {
                    $.each(response['ModelState']['book.Year'], function (index, item) {
						$('#errors').append("<p>" + item + "</p>");
                    });
                }
            }
        });
    }
})
</script>
</body>
</html>

Для вывода ошибок здесь определен специальный блок с id="errors". При получении ошибки срабатывает функция error, первый параметр которой хранит все данные об ошибке, в том числе и посланный объект ModelState. Но чтобы обратиться к ошибкам, надо пройти несколько уровней вложенности. Например, чтобы получить ошибки свойства Year, придется использовать вызов response['ModelState']['book.Year']. Получение сообщения об ошибках происходит по тем же ключам, которые были определены в контроллере. Причем каждый из таких вызовов представляет собой массив.

И теперь если мы введем некорретные данные, мы получим сообщения об ошибках.

Валидация в Web API
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850