Добавление проверки
Примечание
Обновленная версия этого руководства доступна здесь , используя последнюю версию Visual Studio. В новом руководстве используется ASP.NET Core MVC, который предоставляет множество улучшений по сравнению с этим руководством.
В этом руководстве описывается модель MVC ASP.NET Core с контроллерами и представлениями. Razor Pages — это новая альтернатива в ASP.NET Core, модель программирования на основе страниц, которая упрощает и повышает эффективность создания пользовательского веб-интерфейса. Мы рекомендуем ознакомиться с руководством по Razor Pages до версии MVC. Руководство по Razor Pages:
- проще для выполнения;
- охватывает дополнительные возможности;
- Предпочтительный подход к разработке новых приложений.
В этом разделе вы добавите логику проверки в Movie
модель и убедитесь, что правила проверки применяются каждый раз, когда пользователь пытается создать или изменить фильм с помощью приложения.
Хранение вещей DRY
Одним из основных принципов проектирования ASP.NET MVC является DRY ("Не повторяйся"). ASP.NET MVC рекомендует указать функциональные возможности или поведение только один раз, а затем отразить их везде в приложении. Это сокращает объем кода, необходимого для написания, и делает код, который вы пишете, менее подвержен ошибкам и упрощает обслуживание.
Поддержка проверки, предоставляемая ASP.NET MVC и Entity Framework Code First, является отличным примером принципа DRY в действии. Вы можете декларативно указывать правила проверки в одном месте (в классе модели), а правила применяются везде в приложении.
Давайте посмотрим, как можно воспользоваться этой поддержкой проверки в приложении movie.
Добавление правил проверки в модель фильма
Начнем с добавления логики проверки в Movie
класс .
Откройте файл Movie.cs. Обратите внимание, что System.ComponentModel.DataAnnotations
пространство имен не содержит System.Web
. DataAnnotations предоставляет встроенный набор атрибутов проверки, которые можно декларативно применять к любому классу или свойству. (Он также содержит атрибуты форматирования, такие как DataType , которые помогают в форматировании и не обеспечивают никакой проверки.)
Теперь обновите класс, Movie
чтобы воспользоваться встроенными Required
атрибутами , StringLength
, RegularExpression и Range
validation. Замените класс Movie
следующим кодом:
public class Movie
{
public int ID { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[StringLength(5)]
public string Rating { get; set; }
}
Атрибут StringLength
задает максимальную длину строки и устанавливает это ограничение для базы данных, поэтому схема базы данных изменится. Щелкните правой кнопкой мыши таблицу Movies в обозревателе сервера и выберите команду Открыть определение таблицы:
На приведенном выше рисунке показано, как для всех строковых полей задано значение NVARCHAR (MAX). Мы будем использовать миграции для обновления схемы. Выполните сборку решения, а затем откройте окно Консоль диспетчера пакетов и введите следующие команды:
add-migration DataAnnotations
update-database
По завершении этой команды Visual Studio открывает файл класса, определяющий новый DbMigration
производный класс с указанным именем (DataAnnotations
), и в Up
методе можно увидеть код, обновляющий ограничения схемы:
public override void Up()
{
AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
}
Поле Genre
больше не допускает значения NULL (то есть необходимо ввести значение). Максимальная Rating
длина поля — 5, максимальная Title
длина — 60. Минимальная длина 3 в Title
и диапазон в Price
не создавали изменений схемы.
Изучите схему Movie:
В строковых полях отображаются новые ограничения длины и Genre
они больше не проверяются как допускаемые значения NULL.
Атрибуты проверки определяют поведение для свойств модели, к которым они применяются. Атрибуты Required
и MinimumLength
указывают, что свойство должно иметь значение. Тем не менее, чтобы удовлетворить требованиям проверки, пользователю достаточно ввести пробел. Атрибут RegularExpression используется для ограничения того, какие символы могут быть введены. В приведенном выше коде в полях Genre
и Rating
можно использовать только буквы (пробелы, числа и специальные символы не допускаются). Атрибут Range
ограничивает диапазон значений. Атрибут StringLength
позволяет задать максимальную и при необходимости минимальную длину строкового свойства. Типы значений (например decimal, int, float, DateTime
, ) являются обязательными и не нуждаются в атрибуте Required
.
Code First гарантирует, что правила проверки, указанные в классе модели, применяются до того, как приложение сохранит изменения в базе данных. Например, приведенный ниже код создает исключение DbEntityValidationException при SaveChanges
вызове метода , так как отсутствуют несколько обязательных Movie
значений свойств:
MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
db.Movies.Add(movie);
db.SaveChanges(); // <= Will throw server side validation exception
Приведенный выше код создает следующее исключение:
Сбой проверки для одной или нескольких сущностей. Дополнительные сведения см. в разделе Свойство EntityValidationErrors.
Наличие правил проверки, автоматически применяемых платформа .NET Framework, помогает повысить надежность приложения. Это также гарантирует, что в любом случае будут выполнены все проверки и в базе данных не будут случайно оставлены поврежденные данные.
Пользовательский интерфейс ошибки проверки в ASP.NET MVC
Запустите приложение и перейдите по URL-адресу /Movies .
Щелкните ссылку Создать, чтобы добавить новый фильм. Введите в форму какие-либо недопустимые значения. Если функция проверки jQuery на стороне клиента обнаруживает ошибку, сведения о ней отображаются в соответствующем сообщении.
Примечание
Для поддержки проверки jQuery для языковых стандартов, отличных от английского, которые используют запятую (",") для десятичной запятой, необходимо включить nuGet globalize, как описано выше в этом руководстве.
Обратите внимание, что форма автоматически использовала красный цвет границы для выделения текстовых полей, содержащих недопустимые данные, и выдала соответствующее сообщение об ошибке проверки рядом с каждым из них. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).
Реальное преимущество заключается в том, что вам не нужно было изменять одну строку кода в MoviesController
классе или в представлении Create.cshtml , чтобы включить этот пользовательский интерфейс проверки. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie
были применены атрибуты. При проверке с использованием метода действия Edit
применяются те же правила.
Данные формы передаются на сервер только после того, как будут устранены любые ошибки на стороне клиента. Это можно проверить, поместив точку останова в метод HTTP Post с помощью средства fiddler или средств разработчика IE F12.
Как выполняется проверка в представлении создания и методе создания действия
Вам может быть интересно, как пользовательский интерфейс проверки создается без обновления кода контроллера или представлений. В следующем списке Create
показано, как выглядят методы в MovieController
классе . Они не изменяются по сравнению с тем, как вы создали их ранее в этом руководстве.
public ActionResult Create()
{
return View();
}
// POST: /Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
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 в Обозреватель Интернета.
На следующем рисунке показано, как отключить JavaScript в браузере FireFox.
На следующем рисунке показано, как отключить JavaScript в браузере Chrome.
Ниже приведен шаблон представления Create.cshtml , который вы создали ранее в этом руководстве. Он используется в показанных выше методах действия для отображения исходной формы и повторного вывода формы в случае ошибки.
@model MvcMovie.Models.Movie
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
</div>
@*Fields removed for brevity.*@
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Обратите внимание, что код использует вспомогатель Html.EditorFor
для вывода <input>
элемента для каждого Movie
свойства. Рядом с этой вспомогательной функцией находится вызов вспомогательного Html.ValidationMessageFor
метода. Эти два вспомогательных метода работают с объектом модели, который передается контроллером в представление (в данном случае это Movie
объект ). Они автоматически ищут атрибуты проверки, указанные в модели, и отображают сообщения об ошибках соответствующим образом.
Этот подход удобен тем, что ни контроллер, ни шаблон представления Create
ничего не знают о фактически применяемых правилах проверки или отображаемых сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie
. Такие же правила проверки автоматически применяются к представлению Edit
и любым другим представлениям модели, которые вы можете создавать или редактировать.
Если вы хотите изменить логику проверки позже, это можно сделать ровно в одном месте, добавив атрибуты проверки в модель (в этом примере movie
класс ). Вам не придется беспокоиться о несогласованности применения правил в различных частях приложения, поскольку вся логика проверки будет определена в одном месте и начнет применяться по всему приложению. Это позволяет максимально оптимизировать код и обеспечить удобство его совершенствования и поддержки. И это означает, что вы будете полностью соблюдать принцип DRY .
Использование атрибутов DataType
Откройте файл Movie.cs и проверьте класс Movie
. В пространстве имен System.ComponentModel.DataAnnotations
в дополнение к набору встроенных атрибутов проверки предоставляются атрибуты форматирования. К полям с датой выпуска и ценой уже применено значение перечисления DataType
. В следующем коде показаны свойства ReleaseDate
и Price
с соответствующим атрибутом DataType
.
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[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, а для DataType.Date можно предоставить селектор даты в браузерах, поддерживающих HTML5. Атрибуты DataType выдают атрибуты HTML 5 data- (произносится тире данных), которые могут понимать браузеры HTML 5. Атрибуты DataType не обеспечивают никакой проверки.
DataType.Date
не задает формат отображаемой даты. По умолчанию поле данных отображается в соответствии с форматами по умолчанию на основе CultureInfo сервера.
С помощью атрибута DisplayFormat
можно явно указать формат даты:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
Параметр ApplyFormatInEditMode
указывает, что указанное форматирование также должно применяться при отображении значения в текстовом поле для редактирования. (Это может не понадобиться для некоторых полей, например для значений валют, может не потребоваться символ валюты в текстовом поле для редактирования.)
Атрибут DisplayFormat можно использовать сам по себе, но, как правило, рекомендуется также использовать атрибут DataType . Атрибут DataType
передает семантику данных, а не способ их отображения на экране, и предоставляет следующие преимущества, которые вы не получаете с помощью DisplayFormat
:
- В браузере можно включить функции HTML5 (например, для отображения элемента управления календарем, символа валюты, соответствующего языкового стандарта, ссылок на электронную почту и т. д.).
- По умолчанию браузер будет отображать данные в правильном формате в зависимости от вашего языкового стандарта.
- Атрибут DataType позволяет MVC выбрать правильный шаблон поля для отрисовки данных ( displayFormat , если используется сам по себе, использует шаблон строки). Дополнительные сведения см. в разделе Шаблоны ASP.NET MVC 2 Брэда Уилсона. (Хотя эта статья написана для MVC 2, эта статья по-прежнему относится к текущей версии ASP.NET MVC.)
Если вы используете DataType
атрибут с полем даты, необходимо также указать DisplayFormat
атрибут , чтобы убедиться, что поле правильно отображается в браузерах Chrome. Дополнительные сведения см. в этом потоке StackOverflow.
Примечание
Проверка 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; }
[Required,StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"),DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
[Range(1, 100),DataType(DataType.Currency)]
public decimal Price { get; set; }
[Required,StringLength(5)]
public string Rating { get; set; }
}
В следующей части этой серии мы рассмотрим приложение и внесем ряд изменений в автоматически создаваемые методы Details
и Delete
.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по