無須撰寫驗證程式碼,就能間接驗證使用者輸入
您在表單中,指示網站使用者如何正確地完成每項值,同時您也必須檢查他們所輸入的值。 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]
屬性,可確保 Name
和 Price
值必能完成。 此外也使用 [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 會在下列兩個不同的時機執行驗證:
- 欄位驗證會在使用者跳離欄位時執行。 欄位驗證可確保使用者在第一時間知道驗證問題。
- 模型驗證會在使用者提交表單時執行。 模型驗證可確保不會儲存到不正確的資料。
當表單驗證失敗時,訊息會顯示在 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
}
}
}
若改用 OnValidSubmit
和 OnInvalidSubmit
,就無須檢查每個事件處理常式中的驗證狀態:
@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
}
}