Часть 9. Добавление проверки в приложение MVC ASP.NET Core

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

Автор: Рик Андерсон (Rick Anderson)

В этом разделе рассматриваются следующие вопросы.

  • К модели Movie добавляется логика проверки.
  • Убедитесь, что правила проверки применяются каждый раз, когда пользователь создает или редактирует фильм.

Соблюдение принципа "Не повторяйся"

Принцип DRY (от английского "Don't Repeat Yourself" — не повторяйся) является одним из основополагающих принципов разработки в модели MVC. В модели ASP.NET Core MVC рекомендуется задавать функциональные возможности или поведение только один раз, а затем отражать их в других местах в приложении. Это позволяет свести к минимуму объем кода, а также снизить риск возникновения в нем ошибок и упростить его тестирование и поддержку.

Ярким примером применения принципа "Не повторяйся" является поддержка проверки, реализуемая в модели MVC и на платформе Entity Framework Core Code First. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.

Добавление правил проверки к модели фильма

Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType), которые обеспечивают форматирование и не предназначены для проверки.

Movie Обновите класс, чтобы воспользоваться встроенными атрибутами Requiredпроверки , StringLengthRegularExpressionRange и атрибутом DataType форматирования.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Атрибуты проверки определяют поведение для свойств модели, к которым они применяются:

  • Атрибуты Required и MinimumLength указывают, что свойство должно иметь значение. Тем не менее, чтобы удовлетворить требованиям проверки, пользователю достаточно ввести пробел.

  • Атрибут RegularExpression ограничивает набор допустимых для ввода символов. В приведенном выше коде в Genre:

    • должны использоваться только буквы;
    • первая буква должна быть прописной; Пробелы разрешены, а цифры и специальные символы — нет.
  • В RegularExpression Rating:

    • первый символ должен быть прописной буквой;
    • допускаются специальные символы и цифры, а также последующие пробелы. Значение "PG-13" допустимо для рейтинга, но недопустимо для жанра.
  • атрибут Range ограничивает значения указанным диапазоном.

  • Атрибут StringLength позволяет задать максимальную и при необходимости минимальную длину строкового свойства.

  • Типы значений (например, decimal, int, float, DateTime) по своей природе являются обязательными и не требуют атрибута [Required].

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

Интерфейс ошибки при проверке

Запустите приложение и перейдите к контроллеру фильмов.

Щелкните ссылку Создать, чтобы добавить новый фильм. Введите в форму какие-либо недопустимые значения. Если функция проверки jQuery на стороне клиента обнаруживает ошибку, сведения о ней отображаются в соответствующем сообщении.

Форма просмотра фильма с несколькими ошибками проверки jQuery на стороне клиента

Примечание.

Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.

Обратите внимание, что для каждого поля, содержащего недопустимое значение, в форме автоматически отображается соответствующее сообщение об ошибке проверки. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).

Серьезное преимущество заключается в том, что для реализации этого пользовательского интерфейса проверки не требуется изменять код в классе MoviesController или представлении Create.cshtml. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie были применены атрибуты. При проверке с использованием метода действия Edit применяются те же правила.

Данные формы передаются на сервер только после того, как будут устранены все ошибки проверки на стороне клиента. Чтобы проверить это, установите точку останова в методе HTTP Post с помощью инструмента Fiddler или средств разработчика F12.

Принципы работы проверки

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

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Первый метод действия Create (HTTP GET) отображает исходную форму создания. Вторая версия ([HttpPost]) обрабатывает передачу формы. Второй метод Create (версия [HttpPost]) вызывает ModelState.IsValid, который определяет наличие ошибок проверки в фильме. При вызове этого метода оцениваются все атрибуты проверки, которые были применены к объекту. При наличии ошибок проверки в объекте метод Create повторно отображает форму. Если ошибок нет, метод сохраняет новый фильм в базе данных. В этом примере форма передается на сервер только после того, как будут устранены все ошибки проверки, обнаруженные на стороне клиента. Второй метод Create не вызывается до тех пор, пока на стороне клиента присутствуют ошибки проверки. При отключении JavaScript в браузере также отключается проверка на стороне клиента. В этом случае вы можете протестировать метод HTTP POST CreateModelState.IsValid, который обнаруживает наличие ошибок проверки.

Вы можете установить точку останова в метод [HttpPost] Create и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.

На следующем рисунке показано, как отключить JavaScript в браузере Firefox.

Firefox: в разделе

На следующем рисунке показано, как отключить JavaScript в браузере Chrome.

Google Chrome: в разделе Javascript меню

После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.

Отладка Intellisense во время передачи недопустимых данных показывает, что атрибут ModelState.IsValid имеет значение false.

Часть шаблона представления показана в следующей Create.cshtml разметке:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

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

Вспомогательная функция тега Input использует атрибуты DataAnnotations и создает HTML-атрибуты, необходимые для проверки jQuery на стороне клиента. Вспомогательная функция тега Validation отображает ошибки проверки. Дополнительные сведения см. в разделе Проверка.

Этот подход удобен тем, что ни контроллер, ни шаблон представления Create ничего не знают о фактически применяемых правилах проверки или отображаемых сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie. Такие же правила проверки автоматически применяются к представлению Edit и любым другим представлениям модели, которые вы можете создавать или редактировать.

При необходимости вы можете изменить логику проверки в одном месте, добавив атрибуты проверки в модель (в этом примере — в класс Movie). Вам не придется беспокоиться о несогласованности применения правил в различных частях приложения, поскольку вся логика проверки будет определена в одном месте и начнет применяться по всему приложению. Это позволяет максимально оптимизировать код и обеспечить удобство его совершенствования и поддержки. Кроме того, таким образом вы будете полностью соблюдать требования принципа "Не повторяйся".

Использование атрибутов DataType

Откройте файл Movie.cs и проверьте класс Movie. В пространстве имен System.ComponentModel.DataAnnotations в дополнение к набору встроенных атрибутов проверки предоставляются атрибуты форматирования. К полям с датой выпуска и ценой уже применено значение перечисления DataType. В следующем коде показаны свойства ReleaseDate и Price с соответствующим атрибутом DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Атрибуты DataType предоставляют модулю просмотра только рекомендации по форматированию данных, а также другие элементы и атрибуты, например, <a> для URL-адресов и <a href="mailto:EmailAddress.com"> для электронной почты. Используйте атрибут RegularExpression для проверки формата данных. Атрибут DataType позволяет указать тип данных с более точным определением по сравнению со встроенным типом базы данных, но не предназначен для проверки. В этом случае требуется отслеживать только дату, но не время. В перечислении DataType представлено множество типов данных, таких как Date, Time, PhoneNumber, Currency, EmailAddress и другие. Атрибут DataType также обеспечивает автоматическое предоставление функций для определенных типов в приложении. Например, может быть создана ссылка mailto: для DataType.EmailAddress. Также в браузерах с поддержкой HTML5 может быть предоставлен селектор даты для DataType.Date. Атрибуты DataType создают атрибуты HTML 5 data-, которые используются браузерами с поддержкой HTML 5. Атрибуты DataTypeне предназначены для проверки.

DataType.Date не задает формат отображаемой даты. По умолчанию поле данных отображается с использованием форматов, установленных в параметрах CultureInfo сервера.

С помощью атрибута DisplayFormat можно явно указать формат даты:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Параметр ApplyFormatInEditMode указывает, что формат также должен применяться при отображении значения в текстовом поле для редактирования. (В некоторых случаях такое поведение нежелательно. Например, в текстовом поле для редактирования денежных значений обычно не требуется отображать обозначение денежной единицы.)

Атрибут DisplayFormat может использоваться отдельно, однако чаще всего его рекомендуется применять вместе с атрибутом DataType. Атрибут DataType передает семантику данных (в отличие от способа их вывода на экран) и дает следующие преимущества по сравнению с атрибутом DisplayFormat:

  • Поддержка функций HTML5 в браузере (отображение элемента управления календарем, соответствующего языковому стандарту символа валюты, ссылок электронной почты и т. д.)

  • По умолчанию формат отображения данных в браузере определяется в соответствии с установленным языковым стандартом.

  • С помощью атрибута DataType модель MVC может выбрать подходящий шаблон поля для отображения данных (DisplayFormat при отдельном использовании базируется на строковом шаблоне).

Примечание.

Проверка jQuery не работает с атрибутом Range и DateTime. Например, следующий код всегда приводит к возникновению ошибки проверки на стороне клиента, даже если дата попадает в указанный диапазон:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Чтобы использовать атрибут Range с DateTime, необходимо отключить проверку дат jQuery. Как правило, не рекомендуется компилировать модели с фиксированными датами, поэтому использовать атрибуты Range и DateTime следует крайне осторожно.

В следующем коде демонстрируется объединение атрибутов в одной строке:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

В следующей части этой серии мы рассмотрим приложение и внесем ряд изменений в автоматически создаваемые методы Details и Delete.

Дополнительные ресурсы

В этом разделе рассматриваются следующие вопросы.

  • К модели Movie добавляется логика проверки.
  • Убедитесь, что правила проверки применяются каждый раз, когда пользователь создает или редактирует фильм.

Соблюдение принципа "Не повторяйся"

Принцип DRY (от английского "Don't Repeat Yourself" — не повторяйся) является одним из основополагающих принципов разработки в модели MVC. В модели ASP.NET Core MVC рекомендуется задавать функциональные возможности или поведение только один раз, а затем отражать их в других местах в приложении. Это позволяет свести к минимуму объем кода, а также снизить риск возникновения в нем ошибок и упростить его тестирование и поддержку.

Ярким примером применения принципа "Не повторяйся" является поддержка проверки, реализуемая в модели MVC и на платформе Entity Framework Core Code First. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.

Добавление правил проверки к модели фильма

Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType), которые обеспечивают форматирование и не предназначены для проверки.

Movie Обновите класс, чтобы воспользоваться встроенными атрибутами Requiredпроверки , StringLengthRegularExpressionRange и атрибутом DataType форматирования.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Атрибуты проверки определяют поведение для свойств модели, к которым они применяются:

  • Атрибуты Required и MinimumLength указывают, что свойство должно иметь значение. Тем не менее, чтобы удовлетворить требованиям проверки, пользователю достаточно ввести пробел.

  • Атрибут RegularExpression ограничивает набор допустимых для ввода символов. В приведенном выше коде в Genre:

    • должны использоваться только буквы;
    • первая буква должна быть прописной; Пробелы разрешены, а цифры и специальные символы — нет.
  • В RegularExpression Rating:

    • первый символ должен быть прописной буквой;
    • допускаются специальные символы и цифры, а также последующие пробелы. Значение "PG-13" допустимо для рейтинга, но недопустимо для жанра.
  • атрибут Range ограничивает значения указанным диапазоном.

  • Атрибут StringLength позволяет задать максимальную и при необходимости минимальную длину строкового свойства.

  • Типы значений (например, decimal, int, float, DateTime) по своей природе являются обязательными и не требуют атрибута [Required].

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

Интерфейс ошибки при проверке

Запустите приложение и перейдите к контроллеру фильмов.

Щелкните ссылку Создать, чтобы добавить новый фильм. Введите в форму какие-либо недопустимые значения. Если функция проверки jQuery на стороне клиента обнаруживает ошибку, сведения о ней отображаются в соответствующем сообщении.

Форма просмотра фильма с несколькими ошибками проверки jQuery на стороне клиента

Примечание.

Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.

Обратите внимание, что для каждого поля, содержащего недопустимое значение, в форме автоматически отображается соответствующее сообщение об ошибке проверки. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).

Серьезное преимущество заключается в том, что для реализации этого пользовательского интерфейса проверки не требуется изменять код в классе MoviesController или представлении Create.cshtml. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie были применены атрибуты. При проверке с использованием метода действия Edit применяются те же правила.

Данные формы передаются на сервер только после того, как будут устранены все ошибки проверки на стороне клиента. Чтобы проверить это, установите точку останова в методе HTTP Post с помощью инструмента Fiddler или средств разработчика F12.

Принципы работы проверки

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

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Первый метод действия Create (HTTP GET) отображает исходную форму создания. Вторая версия ([HttpPost]) обрабатывает передачу формы. Второй метод Create (версия [HttpPost]) вызывает ModelState.IsValid, который определяет наличие ошибок проверки в фильме. При вызове этого метода оцениваются все атрибуты проверки, которые были применены к объекту. При наличии ошибок проверки в объекте метод Create повторно отображает форму. Если ошибок нет, метод сохраняет новый фильм в базе данных. В этом примере форма передается на сервер только после того, как будут устранены все ошибки проверки, обнаруженные на стороне клиента. Второй метод Create не вызывается до тех пор, пока на стороне клиента присутствуют ошибки проверки. При отключении JavaScript в браузере также отключается проверка на стороне клиента. В этом случае вы можете протестировать метод HTTP POST CreateModelState.IsValid, который обнаруживает наличие ошибок проверки.

Вы можете установить точку останова в метод [HttpPost] Create и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.

На следующем рисунке показано, как отключить JavaScript в браузере Firefox.

Firefox: в разделе

На следующем рисунке показано, как отключить JavaScript в браузере Chrome.

Google Chrome: в разделе Javascript меню

После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.

Отладка Intellisense во время передачи недопустимых данных показывает, что атрибут ModelState.IsValid имеет значение false.

Часть шаблона представления показана в следующей Create.cshtml разметке:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

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

Вспомогательная функция тега Input использует атрибуты DataAnnotations и создает HTML-атрибуты, необходимые для проверки jQuery на стороне клиента. Вспомогательная функция тега Validation отображает ошибки проверки. Дополнительные сведения см. в разделе Проверка.

Этот подход удобен тем, что ни контроллер, ни шаблон представления Create ничего не знают о фактически применяемых правилах проверки или отображаемых сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie. Такие же правила проверки автоматически применяются к представлению Edit и любым другим представлениям модели, которые вы можете создавать или редактировать.

При необходимости вы можете изменить логику проверки в одном месте, добавив атрибуты проверки в модель (в этом примере — в класс Movie). Вам не придется беспокоиться о несогласованности применения правил в различных частях приложения, поскольку вся логика проверки будет определена в одном месте и начнет применяться по всему приложению. Это позволяет максимально оптимизировать код и обеспечить удобство его совершенствования и поддержки. Кроме того, таким образом вы будете полностью соблюдать требования принципа "Не повторяйся".

Использование атрибутов DataType

Откройте файл Movie.cs и проверьте класс Movie. В пространстве имен System.ComponentModel.DataAnnotations в дополнение к набору встроенных атрибутов проверки предоставляются атрибуты форматирования. К полям с датой выпуска и ценой уже применено значение перечисления DataType. В следующем коде показаны свойства ReleaseDate и Price с соответствующим атрибутом DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Атрибуты DataType предоставляют модулю просмотра только рекомендации по форматированию данных, а также другие элементы и атрибуты, например, <a> для URL-адресов и <a href="mailto:EmailAddress.com"> для электронной почты. Используйте атрибут RegularExpression для проверки формата данных. Атрибут DataType позволяет указать тип данных с более точным определением по сравнению со встроенным типом базы данных, но не предназначен для проверки. В этом случае требуется отслеживать только дату, но не время. В перечислении DataType представлено множество типов данных, таких как Date, Time, PhoneNumber, Currency, EmailAddress и другие. Атрибут DataType также обеспечивает автоматическое предоставление функций для определенных типов в приложении. Например, может быть создана ссылка mailto: для DataType.EmailAddress. Также в браузерах с поддержкой HTML5 может быть предоставлен селектор даты для DataType.Date. Атрибуты DataType создают атрибуты HTML 5 data-, которые используются браузерами с поддержкой HTML 5. Атрибуты DataTypeне предназначены для проверки.

DataType.Date не задает формат отображаемой даты. По умолчанию поле данных отображается с использованием форматов, установленных в параметрах CultureInfo сервера.

С помощью атрибута DisplayFormat можно явно указать формат даты:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Параметр ApplyFormatInEditMode указывает, что формат также должен применяться при отображении значения в текстовом поле для редактирования. (В некоторых случаях такое поведение нежелательно. Например, в текстовом поле для редактирования денежных значений обычно не требуется отображать обозначение денежной единицы.)

Атрибут DisplayFormat может использоваться отдельно, однако чаще всего его рекомендуется применять вместе с атрибутом DataType. Атрибут DataType передает семантику данных (в отличие от способа их вывода на экран) и дает следующие преимущества по сравнению с атрибутом DisplayFormat:

  • Поддержка функций HTML5 в браузере (отображение элемента управления календарем, соответствующего языковому стандарту символа валюты, ссылок электронной почты и т. д.)

  • По умолчанию формат отображения данных в браузере определяется в соответствии с установленным языковым стандартом.

  • С помощью атрибута DataType модель MVC может выбрать подходящий шаблон поля для отображения данных (DisplayFormat при отдельном использовании базируется на строковом шаблоне).

Примечание.

Проверка jQuery не работает с атрибутом Range и DateTime. Например, следующий код всегда приводит к возникновению ошибки проверки на стороне клиента, даже если дата попадает в указанный диапазон:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Чтобы использовать атрибут Range с DateTime, необходимо отключить проверку дат jQuery. Как правило, не рекомендуется компилировать модели с фиксированными датами, поэтому использовать атрибуты Range и DateTime следует крайне осторожно.

В следующем коде демонстрируется объединение атрибутов в одной строке:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

В следующей части этой серии мы рассмотрим приложение и внесем ряд изменений в автоматически создаваемые методы Details и Delete.

Дополнительные ресурсы

В этом разделе рассматриваются следующие вопросы.

  • К модели Movie добавляется логика проверки.
  • Убедитесь, что правила проверки применяются каждый раз, когда пользователь создает или редактирует фильм.

Соблюдение принципа "Не повторяйся"

Принцип DRY (от английского "Don't Repeat Yourself" — не повторяйся) является одним из основополагающих принципов разработки в модели MVC. В модели ASP.NET Core MVC рекомендуется задавать функциональные возможности или поведение только один раз, а затем отражать их в других местах в приложении. Это позволяет свести к минимуму объем кода, а также снизить риск возникновения в нем ошибок и упростить его тестирование и поддержку.

Ярким примером применения принципа "Не повторяйся" является поддержка проверки, реализуемая в модели MVC и на платформе Entity Framework Core Code First. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.

Добавление правил проверки к модели фильма

Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType), которые обеспечивают форматирование и не предназначены для проверки.

Обновите класс Movie, чтобы использовать преимущества встроенных атрибутов проверки Required, StringLength, RegularExpression и Range.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string? Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string? Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string? Rating { get; set; }
    }
}

Атрибуты проверки определяют поведение для свойств модели, к которым они применяются:

  • Атрибуты Required и MinimumLength указывают, что свойство должно иметь значение. Тем не менее, чтобы удовлетворить требованиям проверки, пользователю достаточно ввести пробел.

  • Атрибут RegularExpression ограничивает набор допустимых для ввода символов. В приведенном выше коде в Genre:

    • должны использоваться только буквы;
    • первая буква должна быть прописной; Пробелы разрешены, а цифры и специальные символы — нет.
  • В RegularExpression Rating:

    • первый символ должен быть прописной буквой;
    • допускаются специальные символы и цифры, а также последующие пробелы. Значение "PG-13" допустимо для рейтинга, но недопустимо для жанра.
  • атрибут Range ограничивает значения указанным диапазоном.

  • Атрибут StringLength позволяет задать максимальную и при необходимости минимальную длину строкового свойства.

  • Типы значений (например, decimal, int, float, DateTime) по своей природе являются обязательными и не требуют атрибута [Required].

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

Интерфейс ошибки при проверке

Запустите приложение и перейдите к контроллеру фильмов.

Щелкните ссылку Создать, чтобы добавить новый фильм. Введите в форму какие-либо недопустимые значения. Если функция проверки jQuery на стороне клиента обнаруживает ошибку, сведения о ней отображаются в соответствующем сообщении.

Форма просмотра фильма с несколькими ошибками проверки jQuery на стороне клиента

Примечание.

Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.

Обратите внимание, что для каждого поля, содержащего недопустимое значение, в форме автоматически отображается соответствующее сообщение об ошибке проверки. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).

Серьезное преимущество заключается в том, что для реализации этого пользовательского интерфейса проверки не требуется изменять код в классе MoviesController или представлении Create.cshtml. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie были применены атрибуты. При проверке с использованием метода действия Edit применяются те же правила.

Данные формы передаются на сервер только после того, как будут устранены все ошибки проверки на стороне клиента. Чтобы проверить это, установите точку останова в методе HTTP Post с помощью инструмента Fiddler или средств разработчика F12.

Принципы работы проверки

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

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Первый метод действия Create (HTTP GET) отображает исходную форму создания. Вторая версия ([HttpPost]) обрабатывает передачу формы. Второй метод Create (версия [HttpPost]) вызывает ModelState.IsValid, который определяет наличие ошибок проверки в фильме. При вызове этого метода оцениваются все атрибуты проверки, которые были применены к объекту. При наличии ошибок проверки в объекте метод Create повторно отображает форму. Если ошибок нет, метод сохраняет новый фильм в базе данных. В этом примере форма передается на сервер только после того, как будут устранены все ошибки проверки, обнаруженные на стороне клиента. Второй метод Create не вызывается до тех пор, пока на стороне клиента присутствуют ошибки проверки. При отключении JavaScript в браузере также отключается проверка на стороне клиента. В этом случае вы можете протестировать метод HTTP POST CreateModelState.IsValid, который обнаруживает наличие ошибок проверки.

Вы можете установить точку останова в метод [HttpPost] Create и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.

На следующем рисунке показано, как отключить JavaScript в браузере Firefox.

Firefox: в разделе

На следующем рисунке показано, как отключить JavaScript в браузере Chrome.

Google Chrome: в разделе Javascript меню

После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.

Отладка Intellisense во время передачи недопустимых данных показывает, что атрибут ModelState.IsValid имеет значение false.

Часть шаблона представления показана в следующей Create.cshtml разметке:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

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

Вспомогательная функция тега Input использует атрибуты DataAnnotations и создает HTML-атрибуты, необходимые для проверки jQuery на стороне клиента. Вспомогательная функция тега Validation отображает ошибки проверки. Дополнительные сведения см. в разделе Проверка.

Этот подход удобен тем, что ни контроллер, ни шаблон представления Create ничего не знают о фактически применяемых правилах проверки или отображаемых сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie. Такие же правила проверки автоматически применяются к представлению Edit и любым другим представлениям модели, которые вы можете создавать или редактировать.

При необходимости вы можете изменить логику проверки в одном месте, добавив атрибуты проверки в модель (в этом примере — в класс Movie). Вам не придется беспокоиться о несогласованности применения правил в различных частях приложения, поскольку вся логика проверки будет определена в одном месте и начнет применяться по всему приложению. Это позволяет максимально оптимизировать код и обеспечить удобство его совершенствования и поддержки. Кроме того, таким образом вы будете полностью соблюдать требования принципа "Не повторяйся".

Использование атрибутов DataType

Откройте файл Movie.cs и проверьте класс Movie. В пространстве имен System.ComponentModel.DataAnnotations в дополнение к набору встроенных атрибутов проверки предоставляются атрибуты форматирования. К полям с датой выпуска и ценой уже применено значение перечисления DataType. В следующем коде показаны свойства ReleaseDate и Price с соответствующим атрибутом DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }

Атрибуты DataType предоставляют модулю просмотра только рекомендации по форматированию данных, а также другие элементы и атрибуты, например, <a> для URL-адресов и <a href="mailto:EmailAddress.com"> для электронной почты. Используйте атрибут RegularExpression для проверки формата данных. Атрибут DataType позволяет указать тип данных с более точным определением по сравнению со встроенным типом базы данных, но не предназначен для проверки. В этом случае требуется отслеживать только дату, но не время. В перечислении DataType представлено множество типов данных, таких как Date, Time, PhoneNumber, Currency, EmailAddress и другие. Атрибут DataType также обеспечивает автоматическое предоставление функций для определенных типов в приложении. Например, может быть создана ссылка mailto: для DataType.EmailAddress. Также в браузерах с поддержкой HTML5 может быть предоставлен селектор даты для DataType.Date. Атрибуты DataType создают атрибуты HTML 5 data-, которые используются браузерами с поддержкой HTML 5. Атрибуты DataTypeне предназначены для проверки.

DataType.Date не задает формат отображаемой даты. По умолчанию поле данных отображается с использованием форматов, установленных в параметрах CultureInfo сервера.

С помощью атрибута DisplayFormat можно явно указать формат даты:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Параметр ApplyFormatInEditMode указывает, что формат также должен применяться при отображении значения в текстовом поле для редактирования. (В некоторых случаях такое поведение нежелательно. Например, в текстовом поле для редактирования денежных значений обычно не требуется отображать обозначение денежной единицы.)

Атрибут DisplayFormat может использоваться отдельно, однако чаще всего его рекомендуется применять вместе с атрибутом DataType. Атрибут DataType передает семантику данных (в отличие от способа их вывода на экран) и дает следующие преимущества по сравнению с атрибутом DisplayFormat:

  • Поддержка функций HTML5 в браузере (отображение элемента управления календарем, соответствующего языковому стандарту символа валюты, ссылок электронной почты и т. д.)

  • По умолчанию формат отображения данных в браузере определяется в соответствии с установленным языковым стандартом.

  • С помощью атрибута DataType модель MVC может выбрать подходящий шаблон поля для отображения данных (DisplayFormat при отдельном использовании базируется на строковом шаблоне).

Примечание.

Проверка jQuery не работает с атрибутом Range и DateTime. Например, следующий код всегда приводит к возникновению ошибки проверки на стороне клиента, даже если дата попадает в указанный диапазон:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Чтобы использовать атрибут Range с DateTime, необходимо отключить проверку дат jQuery. Как правило, не рекомендуется компилировать модели с фиксированными датами, поэтому использовать атрибуты Range и DateTime следует крайне осторожно.

В следующем коде демонстрируется объединение атрибутов в одной строке:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        public string Title { get; set; }

        [Display(Name = "Release Date"), DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
        public string Genre { get; set; }

        [Range(1, 100), DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
        public string Rating { get; set; }
    }
}

В следующей части этой серии мы рассмотрим приложение и внесем ряд изменений в автоматически создаваемые методы Details и Delete.

Дополнительные ресурсы

В этом разделе рассматриваются следующие вопросы.

  • К модели Movie добавляется логика проверки.
  • Убедитесь, что правила проверки применяются каждый раз, когда пользователь создает или редактирует фильм.

Соблюдение принципа "Не повторяйся"

Принцип DRY (от английского "Don't Repeat Yourself" — не повторяйся) является одним из основополагающих принципов разработки в модели MVC. В модели ASP.NET Core MVC рекомендуется задавать функциональные возможности или поведение только один раз, а затем отражать их в других местах в приложении. Это позволяет свести к минимуму объем кода, а также снизить риск возникновения в нем ошибок и упростить его тестирование и поддержку.

Ярким примером применения принципа "Не повторяйся" является поддержка проверки, реализуемая в модели MVC и на платформе Entity Framework Core Code First. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.

Добавление правил проверки к модели фильма

Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType), которые обеспечивают форматирование и не предназначены для проверки.

Обновите класс Movie, чтобы использовать преимущества встроенных атрибутов проверки Required, StringLength, RegularExpression и Range.

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

Атрибуты проверки определяют поведение для свойств модели, к которым они применяются:

  • Атрибуты Required и MinimumLength указывают, что свойство должно иметь значение. Тем не менее, чтобы удовлетворить требованиям проверки, пользователю достаточно ввести пробел.

  • Атрибут RegularExpression ограничивает набор допустимых для ввода символов. В приведенном выше коде в Genre:

    • должны использоваться только буквы;
    • Первая буква должна быть прописной. Пробелы разрешены, в то время как числа и специальные символы не допускаются.
  • В RegularExpression Rating:

    • первый символ должен быть прописной буквой;
    • допускаются специальные символы и цифры, а также последующие пробелы. Значение "PG-13" допустимо для рейтинга, но недопустимо для жанра.
  • атрибут Range ограничивает значения указанным диапазоном.

  • Атрибут StringLength позволяет задать максимальную и при необходимости минимальную длину строкового свойства.

  • Типы значений (например, decimal, int, float, DateTime) по своей природе являются обязательными и не требуют атрибута [Required].

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

Интерфейс ошибки при проверке

Запустите приложение и перейдите к контроллеру фильмов.

Коснитесь ссылки Create New (Создать), чтобы добавить новый фильм. Введите в форму какие-либо недопустимые значения. Если функция проверки jQuery на стороне клиента обнаруживает ошибку, сведения о ней отображаются в соответствующем сообщении.

Форма просмотра фильма с несколькими ошибками проверки jQuery на стороне клиента

Примечание.

Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.

Обратите внимание, что для каждого поля, содержащего недопустимое значение, в форме автоматически отображается соответствующее сообщение об ошибке проверки. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).

Серьезное преимущество заключается в том, что для реализации этого пользовательского интерфейса проверки не требуется изменять код в классе MoviesController или представлении Create.cshtml. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie были применены атрибуты. При проверке с использованием метода действия Edit применяются те же правила.

Данные формы передаются на сервер только после того, как будут устранены все ошибки проверки на стороне клиента. Чтобы проверить это, установите точку останова в методе HTTP Post с помощью инструмента Fiddler или средств разработчика F12.

Принципы работы проверки

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

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Первый метод действия Create (HTTP GET) отображает исходную форму создания. Вторая версия ([HttpPost]) обрабатывает передачу формы. Второй метод Create (версия [HttpPost]) вызывает ModelState.IsValid, который определяет наличие ошибок проверки в фильме. При вызове этого метода оцениваются все атрибуты проверки, которые были применены к объекту. При наличии ошибок проверки в объекте метод Create повторно отображает форму. Если ошибок нет, метод сохраняет новый фильм в базе данных. В этом примере форма передается на сервер только после того, как будут устранены все ошибки проверки, обнаруженные на стороне клиента. Второй метод Create не вызывается до тех пор, пока на стороне клиента присутствуют ошибки проверки. При отключении JavaScript в браузере также отключается проверка на стороне клиента. В этом случае вы можете протестировать метод HTTP POST CreateModelState.IsValid, который обнаруживает наличие ошибок проверки.

Вы можете установить точку останова в метод [HttpPost] Create и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.

На следующем рисунке показано, как отключить JavaScript в браузере Firefox.

Firefox: в разделе

На следующем рисунке показано, как отключить JavaScript в браузере Chrome.

Google Chrome: в разделе Javascript меню

После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.

Отладка Intellisense во время передачи недопустимых данных показывает, что атрибут ModelState.IsValid имеет значение false.

Часть шаблона представления показана в следующей Create.cshtml разметке:


<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>           
       
        @*Markup removed for brevity.*@

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

Вспомогательная функция тега Input использует атрибуты DataAnnotations и создает HTML-атрибуты, необходимые для проверки jQuery на стороне клиента. Вспомогательная функция тега Validation отображает ошибки проверки. Дополнительные сведения см. в разделе Проверка.

Этот подход удобен тем, что ни контроллер, ни шаблон представления Create ничего не знают о фактически применяемых правилах проверки или отображаемых сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie. Такие же правила проверки автоматически применяются к представлению Edit и любым другим представлениям модели, которые вы можете создавать или редактировать.

При необходимости вы можете изменить логику проверки в одном месте, добавив атрибуты проверки в модель (в этом примере — в класс Movie). Вам не придется беспокоиться о несогласованности применения правил в различных частях приложения, поскольку вся логика проверки будет определена в одном месте и начнет применяться по всему приложению. Это позволяет максимально оптимизировать код и обеспечить удобство его совершенствования и поддержки. Кроме того, таким образом вы будете полностью соблюдать требования принципа "Не повторяйся".

Использование атрибутов DataType

Откройте файл Movie.cs и проверьте класс Movie. В пространстве имен System.ComponentModel.DataAnnotations в дополнение к набору встроенных атрибутов проверки предоставляются атрибуты форматирования. К полям с датой выпуска и ценой уже применено значение перечисления DataType. В следующем коде показаны свойства ReleaseDate и Price с соответствующим атрибутом DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

Атрибуты DataType предоставляют модулю просмотра только рекомендации по форматированию данных, а также другие элементы и атрибуты, например <a> для URL-адресов и <a href="mailto:EmailAddress.com"> для электронной почты. Используйте атрибут RegularExpression для проверки формата данных. Атрибут DataType позволяет указать тип данных с более точным определением по сравнению со встроенным типом базы данных, но не предназначен для проверки. В этом случае требуется отслеживать только дату, но не время. В перечислении DataType представлено множество типов данных, таких как Date, Time, PhoneNumber, Currency, EmailAddress и другие. Атрибут DataType также обеспечивает автоматическое предоставление функций для определенных типов в приложении. Например, может быть создана ссылка mailto: для DataType.EmailAddress. Также в браузерах с поддержкой HTML5 может быть предоставлен селектор даты для DataType.Date. Атрибуты DataType создают атрибуты HTML 5 data-, которые используются браузерами с поддержкой HTML 5. Атрибуты DataTypeне предназначены для проверки.

DataType.Date не задает формат отображаемой даты. По умолчанию поле данных отображается с использованием форматов, установленных в параметрах CultureInfo сервера.

С помощью атрибута DisplayFormat можно явно указать формат даты:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Параметр ApplyFormatInEditMode указывает, что формат также должен применяться при отображении значения в текстовом поле для редактирования. (В некоторых случаях такое поведение нежелательно. Например, в текстовом поле для редактирования денежных значений обычно не требуется отображать обозначение денежной единицы.)

Атрибут DisplayFormat может использоваться отдельно, однако чаще всего его рекомендуется применять вместе с атрибутом DataType. Атрибут DataType передает семантику данных (в отличие от способа их вывода на экран) и дает следующие преимущества по сравнению с атрибутом DisplayFormat:

  • Поддержка функций HTML5 в браузере (отображение элемента управления календарем, соответствующего языковому стандарту символа валюты, ссылок электронной почты и т. д.)

  • По умолчанию формат отображения данных в браузере определяется в соответствии с установленным языковым стандартом.

  • С помощью атрибута DataType модель MVC может выбрать подходящий шаблон поля для отображения данных (DisplayFormat при отдельном использовании базируется на строковом шаблоне).

Примечание.

Проверка jQuery не работает с атрибутом Range и DateTime. Например, следующий код всегда приводит к возникновению ошибки проверки на стороне клиента, даже если дата попадает в указанный диапазон:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Чтобы использовать атрибут Range с DateTime, необходимо отключить проверку дат jQuery. Как правило, не рекомендуется компилировать модели с фиксированными датами, поэтому использовать атрибуты Range и DateTime следует крайне осторожно.

В следующем коде демонстрируется объединение атрибутов в одной строке:

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

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }

    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

В следующей части этой серии мы рассмотрим приложение и внесем ряд изменений в автоматически создаваемые методы Details и Delete.

Дополнительные ресурсы