向模型添加验证 (C#)

作者: 里克·安德森

注意

此处提供了本教程的更新版本,它使用 ASP.NET MVC 5 和 Visual Studio 2013。 它更安全,更易于遵循并演示更多功能。

本教程将介绍如何使用 Microsoft Visual Web Developer 2010 Express Service Pack 1 生成 ASP.NET MVC Web 应用程序的基本知识,这是 visual Studio 的免费 Microsoft版本。 在开始之前,请确保已安装下面列出的先决条件。 可以通过单击以下链接来安装所有这些组件: Web 平台安装程序。 或者,可使用以下链接单独安装各个必备软件:

如果使用 Visual Studio 2010 而不是 Visual Web Developer 2010,请单击以下链接安装必备组件: Visual Studio 2010 先决条件

带有 C# 源代码的 Visual Web 开发人员项目随本主题一起提供。 下载 C# 版本。 如果更喜欢 Visual Basic,请切换到 本教程的 Visual Basic 版本

在本部分中,你将向模型添加验证逻辑 Movie ,并确保每当用户尝试使用应用程序创建或编辑电影时,都会强制实施验证规则。

使事情保持干燥

ASP.NET MVC 的核心设计原则之一是 DRY(“不要重复自己”)。 ASP.NET MVC 鼓励你仅指定一次功能或行为,然后将其反映在应用程序中的任何地方。 这减少了编写所需的代码量,并使你编写的代码更易于维护。

ASP.NET MVC 和 Entity Framework Code First 提供的验证支持是 DRY 原则在操作中的一个很好的示例。 可以在一个位置(在模型类中)声明性地指定验证规则,然后在应用程序中的任何地方强制实施这些规则。

让我们看看如何在电影应用程序中利用此验证支持。

将验证规则添加到电影模型

首先,将一些验证逻辑添加到 Movie 类。

打开 Movie.cs 文件。 在引用System.ComponentModel.DataAnnotations命名空间的文件顶部添加语句using

using System.ComponentModel.DataAnnotations;

命名空间是 .NET Framework 的一部分。 它提供一组内置的验证属性,你可以以声明方式应用于任何类或属性。

现在更新Movie类以利用内置RequiredStringLength属性和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属性指示属性必须具有值;在此示例中,电影必须具有值GenreTitleReleaseDatePrice才能有效。 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 中的验证错误 UI

重新运行应用程序并导航到 /Movies URL。

单击“创建电影”链接以添加新电影。 使用一些无效值填写表单,然后单击“ 创建 ”按钮。

8_validationErrors

请注意,表单自动使用背景色突出显示包含无效数据的文本框,并在每个文本框旁边发出了相应的验证错误消息。 错误消息与在批注 Movie 类时指定的错误字符串匹配。 错误同时强制实施客户端(使用 JavaScript)和服务器端(如果用户禁用 JavaScript)。

真正的好处是,无需更改类或 Create.cshtml 视图中的单个代码MoviesController行才能启用此验证 UI。 本教程前面创建的控制器和视图会自动选取使用模型类的属性 Movie 指定的验证规则。

在“创建视图”和“创建操作”方法中如何进行验证

你可能想知道在不对控制器或视图中的代码进行任何更新的情况下,验证 UI 是如何生成的。 下一个列表显示 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);
}

第一个操作方法显示初始“创建”窗体。 第二个处理表单帖子。 第二 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 类中指定验证规则和错误字符串。

如果以后想要更改验证逻辑,可以在一个位置进行更改。 无需担心对应用程序的不同部分所强制执行规则的方式不一致 - 所有验证逻辑都将定义在一个位置并用于整个应用程序。 这使代码非常简洁,并且更易于维护和改进。 这意味着对 DRY 原则的完全遵守。

向电影模型添加格式

打开 Movie.cs 文件。 除了一组内置的验证特性,System.ComponentModel.DataAnnotations 命名空间还提供格式特性。 你将特性 DisplayFormatDataType 枚举值应用于发布日期和价格字段。 以下代码显示具有适当 DisplayFormat 特性的 ReleaseDatePrice 属性。

[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

在本系列的下一部分中,我们将回顾应用程序,并对自动生成的 DetailsDelete 方法进行一些改进。