無須撰寫驗證程式碼,就能間接驗證使用者輸入

已完成

您在表單中,指示網站使用者如何正確地完成每項值,同時您也必須檢查他們所輸入的值。 Blazor 提供簡單的工具,只需要撰寫一些基本的自訂程式碼,就能執行此項驗證。

您將在本單元中,學習如何標註模型,讓 Blazor 知道需要哪些資料,以及學習如何設定表單來正確驗證及回應使用者資料。

驗證 Blazor 表單中的使用者輸入

當您從網站使用者收集資訊時,檢查資訊及其格式的正確性很重要:

  • 業務層面: 諸如電話號碼或訂單詳細資料等客戶資訊必須正確,才能為使用者提供良好的服務。 例如,您的網頁若能可以在使用者輸入電話號碼時,即使發現格式錯誤,就能日後因為延遲而衍生高額的費用。
  • 技術層面: 您的程式碼若透過表單輸入進行計算或其他處理,不正確的輸入可能會導致錯誤和例外狀況。
  • 基於安全性理由:惡意使用者可能會嘗試利用未檢查的輸入欄位來插入程式碼。

網站使用者知道驗證規則會確認其身分,以及其輸入之資料格式的正確性。 必要欄位通常會標示星號或必要標籤。 當使用者省略值,或是輸入格式不正確的值,將會顯示驗證訊息,指示他們如何更正問題。 當使用者跳離欄位或按一下 [提交] 按鈕時,可能會顯示驗證訊息。

以下是使用者提交無效資料的範例表單。 在此範例中,驗證訊息顯示在表單底部,不正確欄位則以紅色醒目提示。 您將在下一個練習中建置這份表單:

範例表單的螢幕擷取畫面,其中是對輸入無效資料之使用者顯示的的反應。

驗證訊息的內容應盡可能提供實質的幫助。 請勿假設使用者懂得所有事情;例如不一定所有人都知道正確的電子郵件格式。

當您在 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 規則運算式

新增驗證元件至表單

若要設定表單使用資料註釋驗證,請務必先將輸入控制項繫結至模型屬性。 再將 DataAnnotationsValidator 元件新增到 EditForm 元件中的某處。 若要顯示驗證產生的訊息,可使用 ValidationSummary 元件。這會顯示表單中所有控制項的所有驗證訊息。 若希望驗證訊息顯示在每個控制項旁,可使用多個 ValidationMessage 元件。 請務必使用 屬性,將每個ValidationMessageFor 控制項繫結到模型的特定屬性:

@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 會在下列兩個不同的時機執行驗證:

  • 欄位驗證會在使用者跳離欄位時執行。 欄位驗證可確保使用者在第一時間知道驗證問題。
  • 模型驗證會在使用者提交表單時執行。 模型驗證可確保不會儲存到不正確的資料。

當表單驗證失敗時,訊息會顯示在 ValidationSummaryValidationMessage 元件中。 若要自訂這些訊息,可以將屬性新增 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 隨附的標準輸入元素?