ASP.NET Core3.1 MVC 添加验证规则

本节内容:html

  • 向 Movie 模型添加了验证逻辑。
  • 确保每当用户建立或编辑电影时,都会强制执行验证规则。

坚持 DRY 原则

MVC 的设计原则之一是 DRY(“不要自我重复”)。 ASP.NET Core MVC 支持你仅指定一次功能或行为,而后使它应用到整个应用中。 这能够减小所需编写的代码量,并使编写的代码更少出错,更易于测试和维护。jquery

MVC 和 Entity Framework Core Code First 提供的验证支持是 DRY 原则在实际操做中的极佳示例。 能够在一个位置(模型类中)以声明方式指定验证规则,而且在应用中的全部位置强制执行。git

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

DataAnnotations 命名空间提供一组内置验证特性,可经过声明方式应用于类或属性。 DataAnnotations 还包含 DataType 等格式特性,有助于格式设置但不提供任何验证。github

更新 Movie 类以使用内置的 RequiredStringLengthRegularExpression 和 Range 验证特性。数据库

public class Movie
{
    public int Id { get; set; }
 
    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }
 
    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
 
    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
 
    [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }
 
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

 

验证特性指定要对应用这些特性的模型属性强制执行的行为:浏览器

  • Required 和 MinimumLength 特性表示属性必须有值;但用户可输入空格来知足此验证。服务器

  • RegularExpression 特性用于限制可输入的字符。 在上述代码中,即“Genre”(分类):mvc

    • 只能使用字母。
    • 第一个字母必须为大写。 不容许使用空格、数字和特殊字符。
  • RegularExpression“Rating”(分级):async

    • 要求第一个字符为大写字母。
    • 容许在后续空格中使用特殊字符和数字。 “PG-13”对“分级”有效,但对于“分类”无效。
  • Range 特性将值限制在指定范围内。ide

  • StringLength 特性使你可以设置字符串属性的最大长度,以及可选的最小长度。

  • 从本质上来讲,须要值类型(如 decimalintfloatDateTime),但不须要 [Required] 特性。

让 ASP.NET Core 强制自动执行验证规则有助于提高你的应用的可靠性。 同时它能确保你没法忘记验证某些内容,并防止你无心中将错误数据导入数据库。

验证错误 UI

运行应用并导航到电影控制器。

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

带有多个 jQuery 客户端验证错误的电影视图表单

备注

可能没法在小数字段中输入十进制逗号。 若要使 jQuery 验证支持使用逗号(“,”)表示小数点的的非英语区域设置,以及支持非美国英语日期格式,必须执行使应用全球化的步骤。 有关添加十进制逗号的说明,请参阅 GitHub 问题 4076

请注意表单如何自动呈现每一个包含无效值的字段中相应的验证错误消息。 客户端(使用 JavaScript 和 jQuery)和服务器端(若用户禁用 JavaScript)都一定会遇到这些错误。

明显的好处在于不须要在 MoviesController 类或 Create.cshtml 视图中更改单个代码行来启用此验证 UI 。 在本教程前面建立的控制器和视图会自动选取验证规则,这些规则是经过在 Movie 模型类的属性上使用验证特性所指定的。 使用 Edit 操做方法测试验证后,即已应用相同的验证。

存在客户端验证错误时,不会将表单数据发送到服务器。 可经过使用 Fiddler 工具或 F12 开发人员工具在 HTTP Post 方法中设置断点来对此进行验证。

验证工做原理

你可能想知道在不对控制器或视图中的代码进行任何更新的状况下,验证 UI 是如何生成的。 下列代码显示两种 Create 方法。

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}
 
// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

 

第一个 (HTTP GET) Create 操做方法显示初始的“建立”表单。 第二个 ([HttpPost]) 版本处理表单发布。 第二个 Create 方法([HttpPost] 版本)调用 ModelState.IsValid 以检查电影是否有任何验证错误。 调用此方法将评估已应用于对象的任何验证特性。 若是对象有验证错误,则 Create 方法会从新显示此表单。 若是没有错误,此方法则将新电影保存在数据库中。 在咱们的电影示例中,在检测到客户端上存在验证错误时,表单不会发布到服务器。当存在客户端验证错误时,第二个 Create 方法永远不会被调用。 若是在浏览器中禁用 JavaScript,客户端验证将被禁用,而你能够测试 HTTP POST Create 方法 ModelState.IsValid 检测任何验证错误。

能够在 [HttpPost] Create 方法中设置断点,并验证方法从未被调用,客户端验证在检测到存在验证错误时不会提交表单数据。 若是在浏览器中禁用 JavaScript,而后提交错误的表单,将触发断点。 在没有 JavaScript 的状况下仍然能够进行完整的验证。

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

Firefox:在“选项”的“内容”选项卡上,取消选中“启用 Javascript”复选框。

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

Google Chrome:在“内容”设置的 Javascript 部分中,选择“不容许任何网站运行 JavaScript”。

禁用 JavaScript 后,发布无效数据并单步执行调试程序。

在对无效数据进行调试时,ModelState.IsValid 上的 Intellisense 显示值为 false。

Create.cshtml 视图模板的一部分在如下标记中显示 :

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>          
        
        @*Markup removed for brevity.*@

 

操做方法使用上述标记来显示初始表单,并在发生错误时从新显示此表单。

输入标记帮助程序使用 DataAnnotations 特性,并在客户端上生成 jQuery 验证所需的 HTML 特性。 验证标记帮助程序用于显示验证错误。 有关详细信息,请参阅验证

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

须要更改验证逻辑时,能够经过将验证特性添加到模型在同一个位置实现此操做。(在此示例中为 Movie 类)。 无需担忧对应用程序的不一样部分所强制执行规则的方式不一致 - 全部验证逻辑都将定义在一个位置并用于整个应用程序。 这使代码很是简洁,而且更易于维护和改进。 这意味着对 DRY 原则的彻底遵照。

使用 DataType 特性

打开 Movie.cs 文件并检查 Movie 类 。 除了一组内置的验证特性,System.ComponentModel.DataAnnotations 命名空间还提供格式特性。 咱们已经在发布日期和价格字段中应用了 DataType 枚举值。 如下代码显示具备适当 DataType 特性的 ReleaseDate 和 Price 属性。

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
 
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

 

DataType 属性仅提供相关提示来帮助视图引擎设置数据格式(并提供元素/属性,例如向 URL 提供 <a> 和向电子邮件提供 <a href="mailto:EmailAddress.com">)。 可使用 RegularExpression 特性验证数据的格式。 DataType 属性用于指定比数据库内部类型更具体的数据类型,它们不是验证属性。 在此示例中,咱们只想跟踪日期,而不是时间。 DataType 枚举提供了多种数据类型,例如日期、时间、电话号码、货币、电子邮件地址等。 应用程序还可经过 DataType 特性自动提供类型特定的功能。 例如,能够为 DataType.EmailAddress 建立 mailto: 连接,而且能够在支持 HTML5 的浏览器中为 DataType.Date 提供日期选择器。 DataType 特性发出 HTML 5 data-(读做 data dash)特性供 HTML 5 浏览器理解。 DataType 特性不提供任何验证 。

DataType.Date 不指定显示日期的格式。 默认状况下,数据字段根据基于服务器的 CultureInfo 的默认格式进行显示。

DisplayFormat 特性用于显式指定日期格式:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

 

ApplyFormatInEditMode 设置指定在文本框中显示值以进行编辑时也应用格式。 (你可能不想为某些字段执行此操做 — 例如对于货币值,你可能不但愿文本框中的货币符号可编辑。)

能够单独使用 DisplayFormat 特性,但一般建议使用 DataType 特性。 DataType 特性传达数据的语义而不是传达如何在屏幕上呈现数据,并提供 DisplayFormat 不具有的如下优点:

  • 浏览器可启用 HTML5 功能(例如显示日历控件、区域设置适用的货币符号、电子邮件连接等)

  • 默认状况下,浏览器将根据区域设置采用正确的格式呈现数据。

  • DataType 特性使 MVC 可以选择正确的字段模板来呈现数据(若是 DisplayFormat 由自身使用,则使用的是字符串模板)。

备注

jQuery 验证不适用于 Range 属性和 DateTime。 例如,如下代码将始终显示客户端验证错误,即使日期在指定的范围内:

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

须要禁用 jQuery 日期验证才能使用具备 DateTime 的 Range 特性。 一般,在模型中编译固定日期是不恰当的,所以不推荐使用 Range 特性和 DateTime

如下代码显示组合在一行上的特性:

public class Movie
{
    public int Id { get; set; }
 
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
 
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    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)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
 
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

 

在本系列的下一部分中,咱们将回顾应用,并对自动生成的 Details 和 Delete 方法进行一些改进。

其余资源

相关文章
相关标签/搜索