Добавление проверки
Примечание.
Обновленная версия этого руководства доступна здесь , используя последнюю версию 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.cs. Обратите внимание, что System.ComponentModel.DataAnnotations
пространство имен не содержит System.Web
. DataAnnotations предоставляет встроенный набор атрибутов проверки, которые можно применять декларативно к любому классу или свойству. (Он также содержит атрибуты форматирования, такие как DataType , которые помогают в форматировании и не предоставляют никаких проверок.)
Теперь обновите Movie
класс, чтобы воспользоваться встроенными Required
атрибутами , StringLength
RegularExpression и Range
проверки. Замените класс 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
задает максимальную длину строки и задает это ограничение для базы данных, поэтому схема базы данных изменится. Щелкните правой кнопкой мыши таблицу "Фильмы" в обозревателе серверов и щелкните "Открыть определение таблицы":
На рисунке выше вы увидите, что для всех строковых полей задано значение 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
не создавал изменения схемы.
Проверьте схему фильма:
В строковых полях отображаются новые ограничения длины и 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, как описано ранее в этом руководстве.
Обратите внимание, что форма автоматически использовала красный цвет границы, чтобы выделить текстовые поля, содержащие недопустимые данные и создав соответствующее сообщение об ошибке проверки рядом с каждым. Эти ошибки применяются как на стороне клиента (с помощью JavaScript и jQuery), так и на стороне сервера (если пользователь отключает JavaScript).
Реальное преимущество заключается в том, что вам не нужно изменять одну строку кода в MoviesController
классе или в представлении Create.cshtml , чтобы включить этот пользовательский интерфейс проверки. В контроллере и представлениях, создаваемых в рамках этого руководства, автоматически применяются правила проверки, для определения которых к свойствам класса модели Movie
были применены атрибуты. При проверке с использованием метода действия Edit
применяются те же правила.
Данные формы передаются на сервер только после того, как будут устранены любые ошибки на стороне клиента. Это можно проверить, поместив точку останова в метод HTTP Post с помощью средства fiddler или средств разработчика IE F12.
Как выполняется проверка в методе создания представления и создания действия
Вам может быть интересно, как пользовательский интерфейс проверки создается без обновления кода контроллера или представлений. В следующем списке MovieController
показано, как Create
выглядят методы в классе. Они не изменяются из того, как вы создали их ранее в этом руководстве.
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 в Internet Explorer.
На следующем рисунке показано, как отключить 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 предоставляет множество типов данных, таких как Дата, Время, PhoneNumber, Валюта, EmailAddress и многое другое. Атрибут DataType
также обеспечивает автоматическое предоставление функций для определенных типов в приложении. Например, mailto:
ссылку можно создать для DataType.EmailAddress, а селектор дат можно указать для DataType.Date в браузерах, поддерживающих HTML5. Атрибуты DataType выдают атрибуты HTML 5 данных ( выраженные дефисы данных), которые могут понять браузеры 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
.