ASP.NET MVC 5 入门(10):添加验证

原文:https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/getting-started/introduction/adding-validation

作者: Rick Anderson

ASP.NET MVC 5 入门

ASP.NET MVC 5 简介

此教程的更新版本可在此处使用最新版本的Visual Studio 新教程使用ASP.NET CORE MVC,这在本教程中提供了许多改进。

本教程介绍具有控制器和视图的 ASP.NET Core MVC。 Razor 页面是 ASP.NET Core 2.0 中的一个新选择,它是基于页面的编程模型,可以实现更简单、更高效地生成 Web UI。 建议先尝试 Razor 页面教程,再使用 MVC 版本。 Razor 页面教程:

  • 易于关注。
  • 涵盖更多功能。
  • 是开发新应用程序的首选方法。

以下教程系列介绍了GitHub上的 ASP.NET MVC: Source

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

一、使东西干燥

ASP.NET MVC 的核心设计原则之一是晾干("不要自我重复")。 ASP.NET MVC 鼓励您仅指定一次功能或行为,然后让它在应用程序中的任何位置进行反映。 这会减少需要编写的代码量,并使编写的代码更少出错并且更易于维护。

ASP.NET MVC 和实体框架 Code First 提供的验证支持是有效的操作原理示例。 您可以在一个位置(在 model 类中)以声明方式指定验证规则,并在应用程序的任何位置强制执行规则。

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

二、向影片模型添加验证规则

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

打开 Movie.cs 文件。 请注意, System.ComponentModel.DataAnnotations命名空间不包含 System.Web DataAnnotations 提供了一组内置验证特性,可通过声明方式应用于任何类或属性。 (它还包含格式设置属性,如数据类型,可帮助进行格式设置,而不提供任何验证。)

现在更新 Movie 类,以利用内置RequiredStringLengthRegularExpressionRange验证特性。 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's]*$")]
    [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's]*$")]
    [StringLength(5)]
    public string Rating { get; set; }
}

StringLength属性设置字符串的最大长度,并对数据库设置此限制,因此数据库架构将更改。 服务器资源管理器中右键单击电影表,然后单击 "打开表定义":

在上面的图像中,可以看到所有字符串字段均设置为NVARCHAR (MAX) 我们将使用迁移来更新架构。 生成解决方案,然后打开 "包管理器控制台" 窗口并输入以下命令:

add-migration DataAnnotations
update-database

此命令完成后,Visual Studio 会打开类文件,该文件用指定的名称(DataAnnotations)来定义新的 DbMigration 派生类,在 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。 Title 上的最小长度为3,Price 上的范围未创建架构更改。

检查电影架构:

字符串字段显示新的长度限制,并且 Genre 不再被视为可以为 null。

验证特性指定要对应用这些特性的模型属性强制执行的行为。 RequiredMinimumLength 特性表示属性必须有值;但用户可输入空格来满足此验证。 RegularExpression属性用于限制可以输入的字符。 在上述代码中,GenreRating 仅可使用字母(禁用空格、数字和特殊字符)。 Range特性将值限制在指定的范围内。 StringLength 特性使你能够设置字符串属性的最大长度,以及可选的最小长度。 值类型(如 decimal, int, float, DateTime)本质上是必需的,不需要 Required 属性。

Code First 确保在应用程序将更改保存到数据库中之前,强制执行在模型类上指定的验证规则。 例如,当调用 SaveChanges 方法时,以下代码将引发DbEntityValidationException异常,因为缺少几个必需的 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 中的验证错误 UI

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

单击 "新建" 链接以添加新电影。 使用无效值填写表单。 当 jQuery 客户端验证检测到错误时,会显示一条错误消息。

8_validationErrors

Note

若要支持使用逗号(",")作为小数点的非英语区域设置的 jQuery 验证,必须按本教程前面所述包含 NuGet 全球化。

请注意窗体自动使用红色边框颜色突出显示包含无效数据的文本框,并在每个文本框旁边发出适当的验证错误消息。 客户端(使用 JavaScript 和 jQuery)和服务器端(若用户禁用 JavaScript)都必定会遇到这些错误。

真正的好处是,您无需在 MoviesController 类中或在Create. cshtml视图中更改一行代码即可启用此验证 UI。 在本教程前面创建的控制器和视图会自动选取验证规则,这些规则是通过在 Movie 模型类的属性上使用验证特性所指定的。 使用 Edit 操作方法测试验证后,即已应用相同的验证。

存在客户端验证错误时,不会将表单数据发送到服务器。 可以通过使用fiddler 工具或 IE F12 开发人员工具,在 HTTP Post 方法中放置一个断点来验证这一点。

四、如何在 "创建视图" 和 "创建操作" 方法中进行验证

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

第一个 (HTTP GET) Create 操作方法显示初始的“创建”表单。 第二个 ([HttpPost]) 版本处理表单发布。 第二个 Create 方法(HttpPost 版本)检查 ModelState.IsValid,以查看电影是否有任何验证错误。 获取此属性将计算已应用于对象的任何验证特性。 如果对象具有验证错误,则 Create 方法将重新出现该窗体。 如果没有错误,此方法则将新电影保存在数据库中。 在我们的电影示例中,当在客户端检测到验证错误时,表单不会发布到服务器; 第二个Create方法永远不会被调用 如果在浏览器中禁用 JavaScript,则会禁用客户端验证,并 ModelState.IsValid HTTP POST Create 方法来检查电影是否有任何验证错误。

可以在 HttpPost Create 方法中设置断点,并验证方法从未被调用,客户端验证在检测到存在验证错误时不会提交表单数据。 如果在浏览器中禁用 JavaScript,然后提交错误的表单,将触发断点。 在没有 JavaScript 的情况下仍然可以进行完整的验证。 下图显示了如何在 Internet Explorer 中禁用 JavaScript。

以下图片显示如何在 FireFox 浏览器中禁用 JavaScript。

以下图片显示如何在 Chrome 浏览器中禁用 JavaScript。

下面是在本教程的前面部分中基架的Create. view 模板。 以上所示的操作方法使用它来显示初始表单,并在发生错误时重新显示此表单。

@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 帮助器来输出每个 Movie 属性的 <input> 元素。 此帮助器旁边的调用 Html.ValidationMessageFor 帮助器方法。 这两个帮助器方法使用由控制器传递到视图的模型对象(在本例中为 Movie 对象)。 它们会自动查找在模型上指定的验证属性,并根据需要显示错误消息。

此方法真正好的一点是:无论是控制器还是 Create 视图模板都不知道强制实施的实际验证规则或显示的特定错误消息。 仅可在 Movie 类中指定验证规则和错误字符串。 这些相同的验证规则自动应用于 Edit 视图和可能创建用于编辑模型的任何其他视图模板。

如果要在以后更改验证逻辑,可以通过向模型中添加验证特性(在本示例中,是 movie 类),只在一个位置执行此操作。 无需担心对应用程序的不同部分所强制执行规则的方式不一致 - 所有验证逻辑都将定义在一个位置并用于整个应用程序。 这使代码非常简洁,并且更易于维护和改进。 这意味着你将完全遵守晾干原则。

五、使用 DataType 特性

打开 Movie.cs 文件并检查 Movie 除了内置的验证特性集外, System.ComponentModel.DataAnnotations命名空间还提供格式特性。 已将DataType枚举值应用于发布日期和价格字段。 下面的代码演示具有相应DataType特性的 ReleaseDatePrice 属性。

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

DataType特性只为视图引擎提供用于设置数据格式的提示(并为电子邮件提供 URL 的 <a><a href="mailto:EmailAddress.com"> 等属性。 您可以使用RegularExpression属性来验证数据的格式。 DataType特性用于指定比数据库内部类型更具体的数据类型,它们是验证特性。 在此示例中,我们只想跟踪日期,而不是日期和时间。 DataType 枚举提供多种数据类型,例如日期、时间、PhoneNumber、货币、EmailAddress等。 应用程序还可通过 DataType 特性自动提供类型特定的功能。 例如,可以为EmailAddress创建 mailto: 链接,并且可以在支持HTML5的浏览器中为数据类型提供日期选择器。 数据类型属性发出 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 )。 有关详细信息,请参阅 Brad Wilson 的ASP.NET MVC 2 模板 (尽管是针对 MVC 2 编写的,但本文仍适用于当前版本的 ASP.NET MVC。)

如果将 DataType 特性与日期字段结合使用,则还必须指定 DisplayFormat 属性,以确保字段在 Chrome 浏览器中正确呈现。 有关详细信息,请参阅此 StackOverflow 线程

Note

jQuery 验证不能使用范围属性和日期时间 例如,以下代码将始终显示客户端验证错误,即便日期在指定的范围内:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

你将需要禁用 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; }
}

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

原文地址:https://www.cnblogs.com/springsnow/p/13264831.html