隐式验证用户输入,而无需编写验证代码

已完成

在表单中,你应该向网站用户提供有关如何正确填写每个值的说明,但你也应该检查他们输入的值。 Blazor 提供了简单的工具,这些工具可使用最少的自定义代码执行此验证。

在本单元中,你将了解如何对模型进行注释以使 Blazor 知道需要哪些数据,以及如何配置表单以正确地验证和响应用户数据。

验证 Blazor 表单中的用户输入

当你收集来自网站用户的信息时,必须检查其是否有意义且格式是否正确:

  • 出于业务原因:客户信息(例如电话号码或订单详细信息)必须正确无误才能为用户提供优质服务。 例如,如果网页可以在用户输入电话号码时立即发现该号码格式错误,则可以防止以后出现代价高昂的延迟。
  • 出于技术原因:如果代码使用表单输入进行计算或其他处理,则不正确的输入可能会导致错误和异常。
  • 出于安全原因:恶意用户可能会尝试通过利用未经检查的输入字段来注入代码。

网站用户熟悉用于检查其输入的详细信息是否存在以及格式是否正确的验证规则。 必填字段通常标有星号或“必填”标签。 如果他们省略了某个值或输入了格式错误的值,将看到一条指示他们如何解决问题的验证消息。 当用户按 Tab 键离开某个字段或单击“提交”按钮时,可能会显示验证消息

下面是一个示例表单,其中用户提交了无效数据。 在这种情况下,表单底部有验证消息并且无效字段用红色突出显示。 你将在下一练习中生成此表单:

Screenshot of an example form displaying feedback for the user about invalid data.

最好使验证消息尽可能有帮助。 不要假定用户了解所有信息:例如,并非每个人都知道有效电子邮件地址的格式。

在 Blazor 中使用 EditForm 组件时,有多种验证选项可供选择,而无需编写复杂的代码:

  • 在模型中,可以对每个属性使用数据注释来告诉 Blazor 何时需要值以及它们应该采用什么格式。
  • EditForm 组件中,添加 DataAnnotationsValidator 组件,它将根据用户输入的值检查模型注释。
  • 如果希望在提交的表单中显示所有验证消息的摘要,请使用 ValidationSummary 组件。
  • 如果要显示特定模型属性的验证消息,请使用 ValidationMessage 组件。

准备用于验证的模型

首先告诉 DataAnnotationsValidator 组件有效数据的外观。 可以通过在数据模型中使用注释属性来声明验证限制。 请看以下示例:

using  System.ComponentModel.DataAnnotations;

public class Pizza
{
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    
    public string Description { get; set; }
    
    [EmailAddress]
    public string ChefEmail { get; set;}
    
    [Required]
    [Range(10.00, 25.00)]
    public decimal Price { get; set; }
}

我们将在表单中使用此模型,以使 Blazing Pizza 员工能够将新的比萨添加到菜单中。 它包含 [Required] 属性以确保 NamePrice 值始终完整。 它还使用 [Range] 属性来检查输入的比萨价格是否在合理范围内。 最后,它使用 [EmailAddress] 属性来检查输入的 ChefEmail 值是否是有效的电子邮件地址。

可以在模型中使用的其他注释包括:

  • [ValidationNever]:如果要确保该字段从不包含在验证中,请使用此注释。
  • [CreditCard]:如果要记录用户的有效信用卡号,请使用此注释。
  • [Compare]:如果要确保模型中的两个属性匹配,请使用此注释。
  • [Phone]:如果要记录用户的有效电话号码,请使用此注释。
  • [RegularExpression]:如果通过将值与正则表达式进行比较来检查值的格式,请使用此注释。
  • [StringLength]:如果要检查字符串值的长度是否不超过最大长度,请使用此注释。
  • [Url]:如果要记录用户的有效 URL,请使用此注释。

注意

正则表达式广泛用于将字符串与模式进行比较,也用于修改字符串。 可以使用它们来定义表单值必须符合的自定义格式。 要详细了解 .NET 中的正则表达式,请参阅《.NET 正则表达式》。

向表单添加验证组件

要将表单配置为使用数据注释验证,请首先确保已将输入控件绑定到模型属性。 然后,在 EditForm 组件内的某个位置添加 DataAnnotationsValidator 组件。 若要显示验证生成的消息,请使用 ValidationSummary 组件,该组件显示表单中所有控件的所有验证消息。 如果想要在每个控件旁边显示验证消息,请使用多个 ValidationMessage 组件。 请记住,使用 For 属性将每个 ValidationMessage 控件与模型的特定属性相关联:

@page "/admin/createpizza"

<h1>Add a new pizza</h1>

<EditForm Model="@pizza">
    <DataAnnotationsValidator />
    <ValidationSummary />
    
    <InputText id="name" @bind-Value="pizza.Name" />
    <ValidationMessage For="@(() => pizza.Name)" />
    
    <InputText id="description" @bind-Value="pizza.Description" />
    
    <InputText id="chefemail" @bind-Value="pizza.ChefEmail" />
    <ValidationMessage For="@(() => pizza.ChefEmail)" />
    
    <InputNumber id="price" @bind-Value="pizza.Price" />
    <ValidationMessage For="@(() => pizza.Price)" />
</EditForm>

@code {
    private Pizza pizza = new();
}

控制应用的表单验证

Blazor 在两个不同的时间执行验证:

  • 当用户按 Tab 键离开某个字段时,将执行字段验证。 字段验证可确保用户及早了解验证问题。
  • 当用户提交表单时,将执行模型验证。 模型验证可确保不会存储无效数据。

如果表单验证失败,消息将显示在 ValidationSummary 和 ValidationMessage 组件中。 若要自定义这些消息,可以为模型中每个字段的数据注释添加一个 ErrorMessage 属性:

public class Pizza
{
    public int Id { get; set; }
    
    [Required(ErrorMessage = "You must set a name for your pizza.")]
    public string Name { get; set; }
    
    public string Description { get; set; }
    
    [EmailAddress(ErrorMessage = "You must set a valid email address for the chef responsible for the pizza recipe.")]
    public string ChefEmail { get; set;}
    
    [Required]
    [Range(10.00, 25.00, ErrorMessage = "You must set a price between $10 and $25.")]
    public decimal Price { get; set; }
}

内置验证属性用途广泛,你可以使用正则表达式来检查多种文本模式。 但如果具有特定或不寻常的验证要求,则使用内置属性可能无法完全满足这些要求。 在这些情况下,可以创建自定义验证属性。 首先创建一个从 ValidationAttribute 类继承的类并替代 IsValid 方法:

public class PizzaBase : ValidationAttribute
{
    public string GetErrorMessage() => $"Sorry, that's not a valid pizza base.";

    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        if (value != "Tomato" || value != "Pesto")
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

现在,可以在模型类中使用内置属性时,使用自定义验证属性:

public class Pizza
{
    public int Id { get; set; }
    
    [Required(ErrorMessage = "You must set a name for your pizza.")]
    public string Name { get; set; }
    
    public string Description { get; set; }
    
    [EmailAddress(
        ErrorMessage = "You must set a valid email address for the chef responsible for the pizza recipe.")]
    public string ChefEmail { get; set;}
    
    [Required]
    [Range(10.00, 25.00, ErrorMessage = "You must set a price between $10 and $25.")]
    public decimal Price { get; set; }
    
    [PizzaBase]
    public string Base { get; set; }
}

在表单提交时,在服务器端处理表单验证

使用 EditForm 组件时,有三个事件可用于响应表单提交:

  • OnSubmit:无论验证结果如何,只要用户提交表单,就会触发此事件。
  • OnValidSubmit:当用户提交表单并且他们的输入验证通过时,将触发此事件。
  • OnInvalidSubmit:当用户提交表单并且他们的输入验证失败时,将触发此事件。

如果使用 OnSubmit,则不会触发其他两个事件。 可改用 EditContext 参数来检查是否处理输入数据。 如果要编写自己的逻辑来处理表单提交,请使用此事件:

@page "/admin/createpizza"

<h1>Add a new pizza</a>

<EditForm Model="@pizza" OnSubmit=@HandleSubmission>
    <DataAnnotationsValidator />
    <ValidationSummary />
    
    <InputText id="name" @bind-Value="pizza.Name" />
    <ValidationMessage For="@(() => pizza.Name)" />
    
    <InputText id="description" @bind-Value="pizza.Description" />
    
    <InputText id="chefemail" @bind-Value="pizza.ChefEmail" />
    <ValidationMessage For="@(() => pizza.ChefEMail)" />
    
    <InputNumber id="price" @bind-Value="pizza.Price" />
    <ValidationMessage For="@(() => pizza.Price" />
</EditForm>

@code {
    private Pizza pizza = new();
    
    void HandleSubmission(EditContext context)
    {
        bool dataIsValid = context.Validate();
        if (dataIsValid)
        {
            // Store valid data here
        }
    }
}

如果改用 OnValidSubmitOnInvalidSubmit,则不必在每个事件处理程序中检查验证状态:

@page "/admin/createpizza"

<h1>Add a new pizza</a>

<EditForm Model="@pizza" OnValidSubmit=@ProcessInputData OnInvalidSubmit=@ShowFeedback>
    <DataAnnotationsValidator />
    <ValidationSummary />
    
    <InputText id="name" @bind-Value="pizza.Name" />
    <ValidationMessage For="@(() => pizza.Name)" />
    
    <InputText id="description" @bind-Value="pizza.Description" />
    
    <InputText id="chefemail" @bind-Value="pizza.ChefEmail" />
    <ValidationMessage For="@(() => pizza.ChefEMail)" />
    
    <InputNumber id="price" @bind-Value="pizza.Price" />
    <ValidationMessage For="@(() => pizza.Price" />
</EditForm>

@code {
    private Pizza pizza = new();
    
    void ProcessInputData(EditContext context)
    {
        // Store valid data here
    }
    
    void ShowFeedback(EditContext context)
    {
        // Take action here to help the user correct the issues
    }
}

知识检查

1.

在 EditForm 中使用哪个组件来显示验证错误的摘要?

2.

以下哪一项不是 Blazor 随附的标准输入元素?