项目

ASP.NET Core MVC / Razor Pages:表单与验证

ABP 提供基础设施和约定,让创建表单、本地化表单元素显示名称以及处理服务端与客户端验证变得更加容易:

  • abp-dynamic-form 标签助手能够从 C# 模型类自动创建完整表单:生成输入元素,处理本地化和客户端验证。
  • ABP 表单标签助手abp-inputabp-selectabp-radio...)渲染单个表单元素,同时处理本地化和客户端验证。
  • ABP 自动本地化表单元素的显示名称,无需添加 [DisplayName] 属性。
  • 验证错误信息会根据用户文化自动本地化。

本文档重点介绍客户端验证,不涵盖服务端验证。有关服务端验证基础设施,请查阅验证文档

传统方式

在基于 Bootstrap 的典型 ASP.NET Core MVC / Razor Pages 界面中,需要编写如下样板代码来创建一个简单的表单元素:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

如果您需要或偏好这种方式,可以继续使用。然而,ABP 表单标签助手可以用最少的代码实现相同的输出。

ABP 动态表单

abp-dynamic-form 标签助手完全自动化了表单创建过程。以这个模型类为例:

using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;

namespace MyProject.Web.Pages
{
    public class MovieViewModel
    {
        [Required]
        [StringLength(256)]
        public string Name { get; set; }

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

        [Required]
        [TextArea]
        [StringLength(1000)]
        public string Description { get; set; }

        public Genre Genre { get; set; }

        public float? Price { get; set; }

        public bool PreOrder { get; set; }
    }
}

它使用数据注解属性来定义属性的验证规则和 UI 样式。Genre 在此示例中是一个 enum

namespace MyProject.Web.Pages
{
    public enum Genre
    {
        Classic,
        Action,
        Fiction,
        Fantasy,
        Animation
    }
}

为了在 Razor 页面中创建表单,请在您的 PageModel 类中创建一个属性:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MyProject.Web.Pages
{
    public class CreateMovieModel : PageModel
    {
        [BindProperty]
        public MovieViewModel Movie { get; set; }

        public void OnGet()
        {
            Movie = new MovieViewModel();
        }

        public async Task OnPostAsync()
        {
            if (ModelState.IsValid)
            {
                //TODO: 保存电影信息
            }
        }
    }
}

然后您可以在 .cshtml 文件中渲染表单:

@page
@model MyProject.Web.Pages.CreateMovieModel

<h2>创建新电影</h2>

<abp-dynamic-form abp-model="Movie" submit-button="true" />

结果如下图所示:

abp-dynamic-form-result

请参阅下方的本地化与验证部分,了解如何本地化字段显示名称以及验证如何工作。

有关 abp-dynamic-form 标签助手的所有选项,请参阅其专属文档

ABP 表单标签助手

abp-dynamic-form 覆盖了大多数场景,并允许您通过属性控制和自定义表单。

但是,如果您想自己渲染表单主体(例如,您可能希望完全控制表单布局),可以直接使用 ABP 表单标签助手。上面自动生成的表单可以使用 ABP 表单标签助手创建,如下所示:

@page
@model MyProject.Web.Pages.CreateMovieModel

<h2>创建新电影</h2>

<form method="post">
    <abp-input asp-for="Movie.Name"/>
    <abp-input asp-for="Movie.ReleaseDate"/>
    <abp-input asp-for="Movie.Description"/>
    <abp-select asp-for="Movie.Genre"/>
    <abp-input asp-for="Movie.Price"/>
    <abp-input asp-for="Movie.PreOrder"/>
    <abp-button button-type="Primary" type="submit">保存</abp-button>
</form>

有关这些标签助手及其选项的详细信息,请参阅 ABP 表单标签助手文档。

验证与本地化

动态表单和表单标签助手都会基于数据注解属性自动验证输入,并在用户界面上显示验证错误消息。错误消息会根据当前文化自动本地化

示例:用户留空必填字符串属性

abp-form-input-validation-error

如果语言是法语,则显示以下错误消息:

abp-form-input-validation-error

验证错误信息已经翻译成多种语言。您可以按照本地化文档,为您的语言 贡献 翻译或为您的应用程序覆盖文本。

显示名称本地化

ABP 使用属性名称作为用户界面上的字段名称。您通常希望根据当前文化本地化这个名称。

当您将本地化键添加到本地化 JSON 文件时,ABP 可以按照约定本地化 UI 上的字段。

示例:Name 属性的法语本地化(添加到应用程序的 fr.json 文件中):

"Name": "Nom"

然后 UI 将为法语使用给定的名称:

abp-form-input-validation-error

使用 DisplayName: 前缀

如果您的属性名称需要用于其他目的,并且需要一个不同的翻译值,那么直接使用属性名称作为本地化键可能会出现问题。在这种情况下,请使用 DisplayName: 前缀作为本地化键:

"DisplayName:Name": "Nom"

如果 DisplayName:Name 键存在,ABP 会优先使用它而不是 Name 键。

使用自定义本地化键

如果需要,您可以使用 [DisplayName] 属性为特定属性指定本地化键:

[DisplayName("MyNameKey")]
public string Name { get; set; }

在这种情况下,您可以使用键 MyNameKey 向本地化文件添加条目。

如果您使用了 [DisplayName] 但没有向本地化文件添加相应的条目,那么 ABP 会显示给定的键作为字段名称,本例中为 MyNameKey。因此,即使您不需要使用本地化系统,它也提供了一种指定硬编码显示名称的方法。

枚举本地化

枚举成员在可能的情况下也会自动本地化。例如,当我们将 <abp-select asp-for="Movie.Genre"/> 添加到表单中时(就像我们在ABP 表单标签助手部分所做的那样),ABP 可以自动填充枚举成员的本地化名称。要启用此功能,您应该在本地化 JSON 文件中定义本地化值。ABP 表单标签助手部分定义的 Genre 枚举的示例条目:

"Enum:Genre.0": "经典电影",
"Enum:Genre.1": "动作电影",
"Enum:Genre.2": "科幻",
"Enum:Genre.3": "奇幻",
"Enum:Genre.4": "动画/卡通"

您可以使用以下任一语法作为本地化键:

  • Enum:<enum-type-name>.<enum-value>
  • <enum-type-name>.<enum-value>

请记住,如果您不为枚举指定值,值将从 0 开始排序。

MVC 标签助手也支持使用枚举成员名称而不是值(例如,您可以定义 "Enum:Genre.Action" 而不是 "Enum:Genre.1"),但不建议这样做。因为当您将枚举属性序列化为 JSON 并发送到客户端时,默认序列化程序使用枚举值而不是枚举名称。因此,枚举名称将不可用于客户端,如果您想在客户端使用相同的本地化值,这将是一个问题。

另请参阅

在本文档中