练习 - 将服务器端和客户端数据验证添加到地址表单

已完成

Blazor 可以将表单绑定到应用程序中的模型。 如果用数据注释来修饰这些模型,则可以在不编写更多代码的情况下进行客户端验证和服务器端验证。

如果客户端未输入姓名和一些地址字段,则该应用不能正确下单。 团队希望你增强验证以添加更多字段。 他们还希望具有一些最小长度和字符验证。

在本练习中,你将替换当前的服务器端验证,以使用数据注释。 你将了解如何管理验证消息并改进现成的验证支持。 在最后一步中,将控制表单的提交方式,只有在所有字段均有效时才能提交表单。

向 Blazor 模型添加数据注释

  1. 在 Visual Studio Code 的文件资源管理器中,展开“模型”,然后选择“Address.cs”。

  2. 在类的顶部添加对 System.ComponentModel.DataAnnotations 的引用。

    using System.ComponentModel.DataAnnotations;
    
  3. 对于每个必填字段,请添加数据注释。

    public class Address
    {
        public int Id { get; set; }
    
        [Required, MinLength(3), MaxLength(100)]
        public string Name { get; set; }
    
        [Required, MinLength(5), MaxLength(100)]
        public string Line1 { get; set; }
    
        [MaxLength(100)]
        public string Line2 { get; set; }
    
        [Required, MinLength(3), MaxLength(50)]
        public string City { get; set; }
    
        [Required, MinLength(3), MaxLength(20)]
        public string Region { get; set; }
    
        [Required, RegularExpression(@"^([0-9]{5})$")]
        public string PostalCode { get; set; }
    }
    
  4. 在文件资源管理器中,展开“页面”,然后选择“Checkout.razor”。

  5. 在结尾 </EditForm> 标记的上方,添加验证摘要和数据注释验证程序。

        <ValidationSummary />
        <DataAnnotationsValidator />
      </EditForm>
    </div>
    
  6. 在 EditForm 标记中,替换 OnSubmit 参数以使用有效提交。

      <EditForm Model=Order.DeliveryAddress OnValidSubmit=PlaceOrder>
    
  7. 现在可以删除自定义服务器端逻辑,以测试该地址是否有效。 删除 @code 块中的 CheckSubmission 方法。

测试新的数据注释验证

  1. 在 Visual Studio Code 中,按 F5 或选择“运行”>“开始调试”。

    尝试在不输入任何信息的情况下订购一些比萨,然后尝试输入不完整的信息。 查看每个字段的详细错误消息。

    Screenshot of the error messages for each field.

    此交互改进了每个字段的错误检查,但是每个字段的出错情况要比旁边的相关字段好得多。

  2. Shift + F5 停止正在运行的应用。

改进 EditFrom 错误消息

  1. 在文件资源管理器中,展开“页面”,然后选择“Checkout.razor”。

  2. 删除 Blazor <ValidationSummary /> 组件。

            <DataAnnotationsValidator />
      </EditForm>
    </div>
    
  3. 在文件资源管理器中,展开“共享”,然后选择“AddressEditor.razor”。

  4. 在每个字段下方添加自定义验证消息。

    <div class="form-field">
        <label>Name:</label>
        <div>
            <InputText @bind-Value="Address.Name" />
            <ValidationMessage For="@(() => Address.Name)" />
        </div>
    </div>
    
    <div class="form-field">
        <label>Line 1:</label>
        <div>
            <InputText @bind-Value="Address.Line1" />
            <ValidationMessage For="@(() => Address.Line1)" />
        </div>
    </div>
    
    <div class="form-field">
        <label>Line 2:</label>
        <div>
            <InputText @bind-Value="Address.Line2" />
            <ValidationMessage For="@(() => Address.Line2)" />
        </div>
    </div>
    
    <div class="form-field">
        <label>City:</label>
        <div>
            <InputText @bind-Value="Address.City" />
            <ValidationMessage For="@(() => Address.City)" />
        </div>
    </div>
    
    <div class="form-field">
        <label>Region:</label>
        <div>
            <InputText @bind-Value="Address.Region" />
            <ValidationMessage For="@(() => Address.Region)" />
        </div>
    </div>
    
    <div class="form-field">
        <label>Postal code:</label>
        <div>
            <InputText @bind-Value="Address.PostalCode" />
            <ValidationMessage For="@(() => Address.PostalCode)" />
        </div>
    </div>
    
  5. 在文件资源管理器中,展开“模型”,然后选择“Address.cs”。

  6. 为每个字段的数据注释添加自定义错误消息。

    public class Address
    {
        public int Id { get; set; }
    
        [Required, MinLength(3, ErrorMessage = "Please use a Name bigger than 3 letters."), MaxLength(100, ErrorMessage = "Please use a Name less than 100 letters.")]
        public string Name { get; set; }
    
        [Required, MinLength(5, ErrorMessage = "Please use an Address bigger than 5 letters."), MaxLength(100, ErrorMessage = "Please use an Address less than 100 letters.")]
        public string Line1 { get; set; }
    
        [MaxLength(100)]
        public string Line2 { get; set; }
    
        [Required, MinLength(3, ErrorMessage = "Please use a City bigger than 3 letters."), MaxLength(50, ErrorMessage = "Please use a City less than 50 letters.")]
        public string City { get; set; }
    
        [Required, MinLength(3, ErrorMessage = "Please use a Region bigger than 3 letters."), MaxLength(20, ErrorMessage = "Please use a Region less than 20 letters.")]
        public string Region { get; set; }
    
        [Required, RegularExpression(@"^([0-9]{5})$", ErrorMessage = "Please use a valid Postal Code with five numbers.")]
        public string PostalCode { get; set; }
    }
    

测试新的数据注释验证

  1. 在 Visual Studio Code 中,按 F5 或选择“运行”>“开始调试”。

    Animated gif showing the error messages for each field being displayed when the data is invalid.

    地址表单会在包含无效数据的字段下方动态显示错误消息。 此交互发生在客户端,可防止客户输入错误地址。

  2. Shift + F5 停止正在运行的应用。

还原整个错误信息并禁用“提交”按钮

  1. 在文件资源管理器中,展开“页面”,然后选择“Checkout.razor”。

  2. 添加将调用 EditForm 组件的 ShowError 方法的 OnInvalidSubmit 参数。

    <EditForm Model=Order.DeliveryAddress OnValidSubmit=PlaceOrder OnInvalidSubmit=ShowError> 
    
  3. 添加更新 isError 属性的 ShowError 方法。

    protected void ShowError()
    {
        isError = true;
    }     
    
  4. 更改 PlaceOrder 方法以更新 isErrorisSubmitting 属性。

    async Task PlaceOrder()
    {
        isError = false;
        isSubmitting = true;
        var response = await HttpClient.PostAsJsonAsync(
            $"{NavigationManager.BaseUri}orders", OrderState.Order);
        var newOrderId= await response.Content.ReadFromJsonAsync<int>();
        OrderState.ResetOrder();
        NavigationManager.NavigateTo($"myorders/{newOrderId}");
    } 
    
  5. 在 Visual Studio Code 中,按 F5 或选择“运行”>“开始调试”。

    Screenshot of the overall error message being shown.

    如果客户尝试提交无效表单,将显示错误消息。

  6. Shift + F5 停止正在运行的应用。

当所有字段都正确时,启用“提交”按钮

客户在完成所有字段之前无法提交订单是否会提供更好的用户体验? 让我们更改结帐页面以满足此要求。 更改 EditForm 以使用 EditContext(而不是模型)。

  1. 在文件资源管理器中,展开“页面”,然后选择“Checkout.razor”。

  2. 更新 EditFrom 元素。

    <EditForm EditContext=editContext OnValidSubmit=PlaceOrder> 
    
  3. 更改按钮元素以使用 isError 参数。

    <button class="checkout-button btn btn-warning" type="Submit" disabled=@isError>
    
  4. @code 块中,为新的 EditContext 添加一个声明。

    private EditContext editContext;
    
  5. 使用订单派送地址初始化上下文。

    protected override void OnInitialized()
    {
        editContext = new(Order.DeliveryAddress);
        editContext.OnFieldChanged += HandleFieldChanged;
    }    
    

    此代码还允许在更改字段时链接事件处理程序。 在新的处理程序中,可以检查模型是否有效以及是否相应地设置 isError

        private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
        {
            isError = !editContext.Validate();
            StateHasChanged();
        }
    
  6. 由于现在已经创建了一个事件处理程序,因此我们应在结帐组件不再需要它时将其释放。

    public void Dispose()
    {
        editContext.OnFieldChanged -= HandleFieldChanged;
    }
    
  7. 若要实现 Dispose 此功能,还必须让 Blazor 知道。 在页面顶部的 @inject 语句下方添加此代码。

    @implements IDisposable
    
  8. 删除对 isSubmitting 的所有引用并更新 PlaceOrder 方法。

    async Task PlaceOrder()
    {
      var response = await HttpClient.PostAsJsonAsync(NavigationManager.BaseUri + "orders", OrderState.Order);
      var newOrderId= await response.Content.ReadFromJsonAsync<int>();
      OrderState.ResetOrder();
      NavigationManager.NavigateTo($"myorders/{newOrderId}");
    }    
    
  9. 在 Visual Studio Code 中,按 F5 或选择“运行”>“开始调试”。

    Animated gif showing that the Place order button is disabled until all the fields have correct values.

    此时系统会提示客户输入信息,并开始禁用“下单”按钮。 只有在所有必填字段都包含数据后,按钮才会变得可点击。

  10. Shift + F5 停止正在运行的应用。