Часть 9. Добавление проверки в приложение MVC ASP.NET Core
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Автор: Рик Андерсон (Rick Anderson)
В этом разделе рассматриваются следующие вопросы.
- К модели
Movie
добавляется логика проверки. - Убедитесь, что правила проверки применяются каждый раз, когда пользователь создает или редактирует фильм.
Соблюдение принципа "Не повторяйся"
Принцип DRY (от английского "Don't Repeat Yourself" — не повторяйся) является одним из основополагающих принципов разработки в модели MVC. В модели ASP.NET Core MVC рекомендуется задавать функциональные возможности или поведение только один раз, а затем отражать их в других местах в приложении. Это позволяет свести к минимуму объем кода, а также снизить риск возникновения в нем ошибок и упростить его тестирование и поддержку.
Поддержка проверки, предоставляемая MVC и Entity Framework Core, является хорошим примером принципа DRY в действии. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.
Удаление ранее измененных данных
На следующем шаге добавляются правила проверки, которые не разрешают значения NULL.
Запустите приложение, перейдите к /Movies/Index
ней, удалите все перечисленные фильмы и остановите приложение. Приложение будет использовать начальные данные при следующем запуске.
Добавление правил проверки к модели фильма
Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType
), которые обеспечивают форматирование и не предназначены для проверки.
Movie
Обновите класс, чтобы воспользоваться встроенными атрибутами Required
проверки , StringLength
RegularExpression
Range
и атрибутом 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 для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий 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 Create
ModelState.IsValid
, который обнаруживает наличие ошибок проверки.
Вы можете установить точку останова в метод [HttpPost] Create
и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.
На следующем рисунке показано, как отключить JavaScript в браузере Firefox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.
Часть шаблона представления показана в следующей 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. Правила проверки декларативно определяются в одном месте (в классе модели) и затем применяются в рамках всего приложения.
Удаление ранее измененных данных
На следующем шаге добавляются правила проверки, которые не разрешают значения NULL.
Запустите приложение, перейдите к /Movies/Index
ней, удалите все перечисленные фильмы и остановите приложение. Приложение будет использовать начальные данные при следующем запуске.
Добавление правил проверки к модели фильма
Пространство имен DataAnnotations предоставляет набор встроенных атрибутов проверки, которые декларативно применяются к классу или свойству. Кроме того, DataAnnotations содержит атрибуты форматирования (такие как DataType
), которые обеспечивают форматирование и не предназначены для проверки.
Movie
Обновите класс, чтобы воспользоваться встроенными атрибутами Required
проверки , StringLength
RegularExpression
Range
и атрибутом 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 для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий 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 Create
ModelState.IsValid
, который обнаруживает наличие ошибок проверки.
Вы можете установить точку останова в метод [HttpPost] Create
и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.
На следующем рисунке показано, как отключить JavaScript в браузере Firefox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.
Часть шаблона представления показана в следующей 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
и атрибутом 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 для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий 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 Create
ModelState.IsValid
, который обнаруживает наличие ошибок проверки.
Вы можете установить точку останова в метод [HttpPost] Create
и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.
На следующем рисунке показано, как отключить JavaScript в браузере Firefox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.
Часть шаблона представления показана в следующей 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 для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий 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 Create
ModelState.IsValid
, который обнаруживает наличие ошибок проверки.
Вы можете установить точку останова в метод [HttpPost] Create
и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.
На следующем рисунке показано, как отключить JavaScript в браузере Firefox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.
Часть шаблона представления показана в следующей 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 для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий 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 Create
ModelState.IsValid
, который обнаруживает наличие ошибок проверки.
Вы можете установить точку останова в метод [HttpPost] Create
и убедиться, что он не вызывается и данные формы не передаются, если на стороне клиента присутствуют ошибки проверки. Если отключить JavaScript в браузере и отправить форму с ошибками, будет достигнута точка останова. Без JavaScript вы по-прежнему будете получать полную проверку.
На следующем рисунке показано, как отключить JavaScript в браузере Firefox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
После отключения JavaScript передайте недопустимые данные и запустите отладку в пошаговом режиме.
Часть шаблона представления показана в следующей 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
.
Дополнительные ресурсы
ASP.NET Core