将验证添加到 ASP.NET Core Razor 页面Add validation to an ASP.NET Core Razor Page

本文内容

作者:Rick Anderson

本部分中向 Movie 模型添加了验证逻辑。每当用户创建或编辑电影时,都会强制执行验证规则。

验证Validation

软件开发的一个关键原则被称为 DRY(即“不要自我重复”) 。Razor 页面鼓励进行仅指定一次功能的开发,且功能在整个应用中反映。DRY 可以帮助:

  • 减少应用中的代码量。
  • 使代码更加不易出错,且更易于测试和维护。

Razor 页面和 Entity Framework 提供的验证支持是 DRY 原则的极佳示例。验证规则在模型类中的某处以声明方式指定,且在应用的所有位置强制执行。

将验证规则添加到电影模型Add validation rules to the movie model

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

更新 Movie 类以使用内置的 RequiredStringLengthRegularExpressionRange 验证特性。

  1. public class Movie
  2. {
  3. public int ID { get; set; }
  4. [StringLength(60, MinimumLength = 3)]
  5. [Required]
  6. public string Title { get; set; }
  7. [Display(Name = "Release Date")]
  8. [DataType(DataType.Date)]
  9. public DateTime ReleaseDate { get; set; }
  10. [Range(1, 100)]
  11. [DataType(DataType.Currency)]
  12. [Column(TypeName = "decimal(18, 2)")]
  13. public decimal Price { get; set; }
  14. [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
  15. [Required]
  16. [StringLength(30)]
  17. public string Genre { get; set; }
  18. [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
  19. [StringLength(5)]
  20. [Required]
  21. public string Rating { get; set; }
  22. }

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

  • RequiredMinimumLength 特性表示属性必须有值;但用户可输入空格来满足此验证。

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

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

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

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

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

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

Razor 页面中的“验证错误”UIValidation Error UI in Razor Pages

运行应用并导航到“页面/电影”。

选择“新建”链接 。使用无效值填写表单。当 jQuery 客户端验证检测到错误时,会显示一条错误消息。

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

备注

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

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

一项重要优势是,无需在“创建”或“编辑”页面中更改代码 。在模型应用 DataAnnotations 后,即已启用验证 UI。本教程中自动创建的 Razor 页面自动选取了验证规则(使用 Movie 模型类的属性上的验证特性)。使用“编辑”页面测试验证后,即已应用相同验证。

存在客户端验证错误时,不会将表单数据发布到服务器。请通过以下一种或多种方法验证是否未发布表单数据:

  • OnPostAsync 方法中放置一个断点。提交表单(选择“创建”或“保存”) 。从未命中断点。
  • 使用 Fiddler 工具
  • 使用浏览器开发人员工具监视网络流量。

服务器端验证Server-side validation

在浏览器中禁用 JavaScript 后,提交出错表单将发布到服务器。

(可选)测试服务器端验证:

  • 在浏览器中禁用 JavaScript。可以使用浏览器的开发人员工具禁用 JavaScript。如果无法在浏览器中禁用 JavaScript,请尝试其他浏览器。

  • 在“创建”或“编辑”页面的 OnPostAsync 方法中设置断点。

  • 提交包含无效数据的表单。

  • 验证模型状态是否无效:

  1. if (!ModelState.IsValid)
  2. {
  3. return Page();
  4. }

或者可以禁用服务器上的客户端验证

以下代码显示了之前在本教程中设定其基架的“Create.cshtml”的一部分 。它用于在“创建”和“编辑”页面中显示初始表单并在发生错误后重新显示表单。

  1. <form method="post">
  2. <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  3. <div class="form-group">
  4. <label asp-for="Movie.Title" class="control-label"></label>
  5. <input asp-for="Movie.Title" class="form-control" />
  6. <span asp-validation-for="Movie.Title" class="text-danger"></span>
  7. </div>

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

“创建”和“编辑”页面中没有验证规则。仅可在 Movie 类中指定验证规则和错误字符串。这些验证规则将自动应用于编辑 Movie 模型的 Razor 页面。

需要更改验证逻辑时,也只能在该模型中更改。将始终在整个应用程序中应用验证(在一处定义验证逻辑)。单处验证有助于保持代码干净,且更易于维护和更新。

使用 DataType 特性Using DataType Attributes

检查 Movie 类。除了一组内置的验证特性,System.ComponentModel.DataAnnotations 命名空间还提供格式特性。DataType 特性应用于 ReleaseDatePrice 属性。

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

DataType 特性仅提供相关提示来帮助视图引擎设置数据格式(并提供特性,例如向 URL 提供 <a> 和向电子邮件提供 <a href="mailto:EmailAddress.com">)。使用 RegularExpression 特性验证数据的格式。DataType 属性用于指定比数据库内部类型更具体的数据类型。DataType 特性不是验证特性。示例应用程序中仅显示日期,不显示时间。

DataType 枚举提供了多种数据类型,例如日期、时间、电话号码、货币、电子邮件地址等。应用程序还可通过 DataType 特性自动提供类型特定的功能。例如,可为 DataType.EmailAddress 创建 mailto: 链接。可在支持 HTML5 的浏览器中为 DataType.Date 提供日期选择器。DataType 特性发出 HTML 5 data-(读作 data dash)特性供 HTML 5 浏览器使用。DataType 特性不提供任何验证 。

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

要使 Entity Framework Core 能将 Price 正确地映射到数据库中的货币,则必须使用 [Column(TypeName = "decimal(18, 2)")] 数据注释。有关详细信息,请参阅数据类型

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

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

ApplyFormatInEditMode 设置用于指定在显示值进行编辑时需应用格式。可能不希望某些字段具有此行为。例如,在货币值中,可能不希望编辑 UI 中存在货币符号。

可单独使用 DisplayFormat 特性,但通常建议使用 DataType 特性。DataType 特性传达数据的语义而不是传达如何在屏幕上呈现数据,并提供 DisplayFormat 不具备的以下优势:

  • 浏览器可启用 HTML5 功能(例如显示日历控件、区域设置适用的货币符号、电子邮件链接等)
  • 默认情况下,浏览器将根据区域设置采用正确的格式呈现数据。
  • 借助 DataType 特性,ASP.NET Core 框架可选择适当的字段模板来呈现数据。单独使用时,DisplayFormat 特性将使用字符串模板。

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

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

通常,在模型中编译固定日期是不恰当的,因此不推荐使用 Range 特性和 DateTime

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

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

Razor Pages 和 EF Core 入门显示了 Razor Pages 的高级 EF Core 操作。

应用迁移Apply migrations

应用于类的 DataAnnotations 会更改架构。例如,应用于 Title 字段的 DataAnnotations 会:

  1. [StringLength(60, MinimumLength = 3)]
  2. [Required]
  3. public string Title { get; set; }
  • 将字符数限制为 60。
  • 不允许使用 null 值。

Movie 表当前具有以下架构:

  1. CREATE TABLE [dbo].[Movie] (
  2. [ID] INT IDENTITY (1, 1) NOT NULL,
  3. [Title] NVARCHAR (MAX) NULL,
  4. [ReleaseDate] DATETIME2 (7) NOT NULL,
  5. [Genre] NVARCHAR (MAX) NULL,
  6. [Price] DECIMAL (18, 2) NOT NULL,
  7. [Rating] NVARCHAR (MAX) NULL,
  8. CONSTRAINT [PK_Movie] PRIMARY KEY CLUSTERED ([ID] ASC)
  9. );

前面的架构更改不会导致 EF 引发异常。不过,请创建迁移,使架构与模型保持一致。

从“工具”菜单中,选择“NuGet 包管理器”>“包管理器控制台”。 在 PMC 中,输入以下命令:

  1. Add-Migration New_DataAnnotations
  2. Update-Database

Update-Database 运行 New_DataAnnotations 类的 Up 方法。检查 Up 方法:

  1. public partial class New_DataAnnotations : Migration
  2. {
  3. protected override void Up(MigrationBuilder migrationBuilder)
  4. {
  5. migrationBuilder.AlterColumn<string>(
  6. name: "Title",
  7. table: "Movie",
  8. maxLength: 60,
  9. nullable: false,
  10. oldClrType: typeof(string),
  11. oldNullable: true);
  12. migrationBuilder.AlterColumn<string>(
  13. name: "Rating",
  14. table: "Movie",
  15. maxLength: 5,
  16. nullable: false,
  17. oldClrType: typeof(string),
  18. oldNullable: true);
  19. migrationBuilder.AlterColumn<string>(
  20. name: "Genre",
  21. table: "Movie",
  22. maxLength: 30,
  23. nullable: false,
  24. oldClrType: typeof(string),
  25. oldNullable: true);
  26. }

更新的 Movie 表具有以下架构:

  1. CREATE TABLE [dbo].[Movie] (
  2. [ID] INT IDENTITY (1, 1) NOT NULL,
  3. [Title] NVARCHAR (60) NOT NULL,
  4. [ReleaseDate] DATETIME2 (7) NOT NULL,
  5. [Genre] NVARCHAR (30) NOT NULL,
  6. [Price] DECIMAL (18, 2) NOT NULL,
  7. [Rating] NVARCHAR (5) NOT NULL,
  8. CONSTRAINT [PK_Movie] PRIMARY KEY CLUSTERED ([ID] ASC)
  9. );

SQLite 不需要迁移。

发布到 AzurePublish to Azure

若要了解如何部署到 Azure,请参阅教程:使用 SQL 数据库在 Azure 中生成 ASP.NET Core 应用

感谢读完这篇 Razor 页面简介。Razor Pages 和 EF Core 入门是本教程的优选后续教程。

其他资源Additional resources

上一篇:添加新字段