Добавление проверки в модель (C#)

по Рик Андерсон (

Note

Обновленная версия этого учебника доступна здесь , в которой используется ASP.NET MVC 5 и Visual Studio 2013. Он более безопасен, гораздо проще следовать и демонстрирует дополнительные функции.

В этом учебнике вы узнаете об основах создания веб-приложения ASP.NET MVC с помощью Microsoft Visual Web Developer 2010 Express с пакетом обновления 1 (SP1), который является бесплатной версией Microsoft Visual Studio. Прежде чем начать, убедитесь, что установлены предварительные требования, перечисленные ниже. Чтобы установить все эти компоненты, щелкните следующую ссылку: установщик веб-платформы. Кроме того, вы можете отдельно установить необходимые компоненты, используя следующие ссылки:

Если вы используете Visual Studio 2010 вместо Visual Web Developer 2010, установите необходимые компоненты, щелкнув следующую ссылку: Предварительные требования для Visual studio 2010.

Для этого раздела доступен проект Visual C# Web Developer с исходным кодом. Скачайте C# версию. Если вы предпочитаете Visual Basic, переключитесь на Visual Basic версию этого учебника.

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

Поддержание СУХИх вещей

Один из основных принципов проектирования ASP.NET MVC — сухой ("принцип"Не повторяйся""). ASP.NET MVC позволяет указать функциональные возможности или поведение только один раз, после чего они будут отражены в любом приложении. Это сокращает объем кода, который необходимо написать, и делает написанный код гораздо проще в обслуживании.

Поддержка проверки, предоставляемая ASP.NET MVC и Entity Framework Code First, является хорошим примером принципа сухой в действии. Правила проверки можно декларативно задавать в одном месте (в классе Model), а затем эти правила применяются везде в приложении.

Рассмотрим, как можно воспользоваться преимуществами этой поддержки проверки в приложении Movie.

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

Начнем с добавления логики проверки к классу Movie.

Откройте файл Movie.cs. Добавьте в начало файла инструкцию using, которая ссылается на пространство имен System.ComponentModel.DataAnnotations :

using System.ComponentModel.DataAnnotations;

Пространство имен является частью .NET Framework. Он предоставляет встроенный набор атрибутов проверки, которые можно декларативно применять к любому классу или свойству.

Теперь обновите класс Movie, чтобы воспользоваться преимуществами встроенных Required, StringLengthи Range атрибутов проверки. Используйте следующий код в качестве примера того, где применять атрибуты.

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

    [Required(ErrorMessage = "Title is required")]
    public string Title { get; set; }

    [Required(ErrorMessage = "Date is required")]
    public DateTime ReleaseDate { get; set; }

    [Required(ErrorMessage = "Genre must be specified")]
    public string Genre { get; set; }

    [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

Атрибуты проверки определяют поведение для свойств модели, к которым они применяются. Атрибут Required указывает, что свойство должно иметь значение. в этом примере фильм должен иметь значения для свойств Title, ReleaseDate, Genreи Price, чтобы быть допустимыми. Атрибут Range ограничивает диапазон значений. Атрибут StringLength позволяет задать максимальную и при необходимости минимальную длину строкового свойства.

Code First гарантирует, что правила проверки, указанные в классе модели, будут применены, прежде чем приложение сохранит изменения в базе данных. Например, приведенный ниже код вызывает исключение при вызове метода SaveChanges, так как отсутствуют несколько обязательных Movie значений свойств и цена равна нулю (за пределами допустимого диапазона).

MovieDBContext db = new MovieDBContext();

Movie movie = new Movie();
movie.Title = "Gone with the Wind";
movie.Price = 0.0M;

db.Movies.Add(movie);
db.SaveChanges();        // <= Will throw validation exception

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

Ниже приведен полный листинг кода для обновленного файла Movie.CS :

using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;

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

        [Required(ErrorMessage = "Title is required")]
        public string Title { get; set; }

        public DateTime ReleaseDate { get; set; }

        [Required(ErrorMessage = "Genre must be specified")]
        public string Genre { get; set; }

        [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }
    }

    public class MovieDBContext : DbContext
    {
        public DbSet<Movie> Movies { get; set; }
    }
}

Пользовательский интерфейс ошибки проверки в ASP.NET MVC

Повторно запустите приложение и перейдите по URL-адресу /Movies .

Щелкните ссылку создать фильм , чтобы добавить новый фильм. Заполните форму недопустимыми значениями и нажмите кнопку " создать ".

8_validationErrors

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

Настоящим преимуществом является то, что вам не пришлось изменять одну строку кода в классе MoviesController или в представлении Create. cshtml , чтобы включить этот пользовательский интерфейс проверки. Контроллер и представления, созданные ранее в этом учебнике, автоматически задают правила проверки, заданные с помощью атрибутов класса модели Movie.

Как выполняется проверка в методе создания представления и создания действия

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

//
// GET: /Movies/Create

public ActionResult Create()
{
    return View();
}

//
// POST: /Movies/Create

[HttpPost]
public ActionResult Create(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(movie);
}

Первый метод действия отображает начальную форму создания. Второй обрабатывает форму Post. Второй метод Create вызывает ModelState.IsValid, чтобы проверить, имеются ли в фильме ошибки проверки. При вызове этого метода оцениваются все атрибуты проверки, которые были применены к объекту. Если объект содержит ошибки проверки, метод Create повторно отображает форму. Если ошибок нет, метод сохраняет новый фильм в базе данных.

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

@model MvcMovie.Models.Movie
@{
    ViewBag.Title = "Create";
}
<h2>
    Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Movie</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Rating)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Rating)
            @Html.ValidationMessageFor(model => model.Rating)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Обратите внимание, что в коде используется вспомогательный метод Html.EditorFor для вывода элемента <input> для каждого свойства Movie. Рядом с этим вспомогательным модулем вызывается вспомогательный метод Html.ValidationMessageFor. Эти два вспомогательных метода работают с объектом модели, который передается контроллером в представление (в данном случае это объект Movie). Они автоматически ищут атрибуты проверки, указанные в модели, и отображают сообщения об ошибках соответствующим образом.

Все, что хорошо замечательно в этом подходе, заключается в том, что ни контроллер, ни шаблон создания представления не знают о фактических правилах проверки, которые применяются, или о конкретных сообщениях об ошибках. Правила проверки и строки ошибок указываются только в классе Movie.

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

Добавление форматирования в модель фильмов

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

[DataType(DataType.Date)] 
public DateTime ReleaseDate { get; set; }

[DataType(DataType.Currency)] 
public decimal Price { get; set; }

Кроме того, можно явно задать значение DataFormatString . В следующем коде показано свойство Дата выпуска со строкой формата даты (а именно, "d"). Этот параметр используется для указания, что вы не хотите использовать время в качестве части даты выпуска.

[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }

Следующий код форматирует свойство Price как денежное.

[DisplayFormat(DataFormatString = "{0:c}")]
public decimal Price { get; set; }

Ниже приведен полный класс Movie.

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

    [Required(ErrorMessage = "Title is required")]
    public string Title { get; set; }

    [DisplayFormat(DataFormatString = "{0:d}")]
    public DateTime ReleaseDate { get; set; }

    [Required(ErrorMessage = "Genre must be specified")]
    public string Genre { get; set; }

    [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
    [DisplayFormat(DataFormatString = "{0:c}")]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

Запустите приложение и перейдите к контроллеру Movies.

8_format_SM

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