練習 - 為地址表單新增伺服器端和用戶端的資料驗證

已完成

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,或選取 [執行] > [開始偵錯]。

    嘗試在不輸入任何資訊的情況下訂購一些披薩,然後輸入不完整的資訊。 觀察每個欄位的詳細錯誤訊息。

    每個欄位之錯誤訊息的螢幕擷取畫面。

    此互動可改進每個欄位的錯誤檢查,但每個欄位的錯誤將會比其相關的前一個欄位更好。

  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,或選取 [執行] > [開始偵錯]。

    此動畫 gif 顯示當資料無效時,每個欄位會顯示的錯誤訊息。

    地址表單會在包含無效資料的欄位下方,動態顯示錯誤訊息。 此互動會在用戶端上發生,避免客戶輸入不正確的地址。

  2. Shift + F5 可阻止應用程式執行。

還原整體錯誤訊息,並停用 [提交] 按鈕

  1. 在 [檔案總管] 中,展開 [頁面],然後選取 [Checkout.razor]

  2. 新增 OnInvalidSubmit 參數,為 EditForm 元件呼叫 ShowError 方法。

    <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,或選取 [執行] > [開始偵錯]。

    所顯示之整體錯誤訊息的螢幕擷取畫面。

    若客戶嘗試提交的表單無效,將會顯示錯誤訊息。

  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,或選取 [執行] > [開始偵錯]。

    此動畫 gif 顯示所有欄位值未完全正確之前,會停用 [下單] 按鈕。

    現在會提示客戶輸入資訊,而且一開始無法使用 [下單] 按鈕。 當在所有必要欄位中輸入資料之後,就可以點選該按鈕。

  10. Shift + F5 可阻止應用程式執行。