注意
這不是這篇文章的最新版本。 關於目前版本,請參閱本文的 .NET 10 版本。
警告
此版本的 ASP.NET Core 已不再支援。 欲了解更多資訊,請參閱.NET及.NET核心支援政策。 關於目前版本,請參閱本文的 .NET 10 版本。
本文說明如何在表單中驗證使用者輸入 Blazor 。
對大多數表單來說,最簡單且推薦的方法是為模型新增資料註解、驗證屬性,並在 中放置DataAnnotationsValidator一個元件。EditForm Blazor 也支援透過表單 EditContext的自訂驗證,無論是直接在表單元件中,或是可重用的驗證器元件中進行。
相關文章提供更多細節:
- 關於撰寫與設定基於模型的驗證規則,包括自訂與非同步規則、巢狀物件驗證及本地化,請參見 ASP.NET Core 中的驗證。
- 關於靜態伺服器端渲染(static SSR)中的即時瀏覽器驗證,請參見 ASP.NET Core Blazor 靜態 SSR 中的客戶端表單驗證。
- 欲了解完整的驗證器元件與遠端驗證實作,請參閱 ASP.NET Core Blazor 進階表單驗證。
- 關於撰寫與設定基於模型的驗證規則與巢狀物件驗證,請參見 ASP.NET Core 中的驗證。
- 欲了解完整的驗證器元件與遠端驗證實作,請參閱 ASP.NET Core Blazor 進階表單驗證。
- 欲了解完整的驗證器元件與遠端驗證實作,請參閱 ASP.NET Core Blazor 進階表單驗證。
用資料註解驗證
以下模型使用 RequiredAttribute 與 RangeAttribute:
Starship.cs:
using System.ComponentModel.DataAnnotations;
public class Starship
{
[Required]
public string? Identifier { get; set; }
[Range(1, 10, ErrorMessage = "Accommodation must be between 1 and 10.")]
public int MaximumAccommodation { get; set; }
}
將模型新增至 EditForm、包含 DataAnnotationsValidator,並使用 ValidationMessage<TValue> 或 ValidationSummary 顯示錯誤。
OnValidSubmit回調僅在驗證成功時被呼叫:
<EditForm Model="Model" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label>
Identifier:
<InputText @bind-Value="Model.Identifier" />
</label>
<ValidationMessage For="() => Model.Identifier" />
</p>
<p>
<label>
Maximum accommodation:
<InputNumber @bind-Value="Model.MaximumAccommodation" />
</label>
<ValidationMessage For="() => Model.MaximumAccommodation" />
</p>
<button type="submit">Submit</button>
</EditForm>
@code {
private Starship Model { get; } = new Starship();
private void Submit()
{
// Process the valid form.
}
}
對於靜態 SSR 表單貼文,指派一個唯一 FormName 並收到已發布的模型,格式為 [SupplyParameterFromForm]:
<EditForm Model="Model" FormName="starship" OnValidSubmit="Submit">
...
</EditForm>
@code {
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
}
如需更多關於在各種轉譯模式下的表單提交與模型繫結的資訊,請參閱 ASP.NET Core Blazor 表單概觀 和 ASP.NET Core Blazor 表單繫結。
若沒有 DataAnnotationsValidator 元件,模型上的驗證屬性不會參與表單的驗證。
執行驗證時
Blazor 執行欄位驗證與完整形式驗證:
- 欄位驗證會在欄位變更後執行。 在互動式表單中,使用者編輯表單時,這會發生在 .NET 檔案中。
- 完整形式驗證通常在
EditForm處理透過OnValidSubmit或OnInvalidSubmit的提交時執行。OnSubmit處理器會控制驗證,如控制表單提交中所述。
靜態 SSR 表單可在靜態 SSR 中提供即時的瀏覽器回饋,並支援 ASP.NET Core Blazor 用戶端表單驗證。 表單發布後會在伺服器上再次權威驗證。
靜態的 SSR 表單會在伺服器上被驗證,且不會在請求間提供即時欄位驗證。
識別成員的驗證結果會與該欄位相關聯。 沒有成員名稱的結果會與模型相關聯,並出現在驗證摘要中,而非欄位的 ValidationMessage 組件。
配置資料註解驗證
DataAnnotationsValidator 一律為表單啟用 DataAnnotations 驗證。 若要使用 Microsoft.Extensions.Validation 套件所提供的擴充驗證功能,請在 AddValidation 檔案中呼叫 Program 擴充方法:
builder.Services.AddValidation();
AddValidation 呼叫會註冊套件的驗證服務,並啟動原始碼產生器,為偵測到的模型類型建立驗證中繼資料。 可用的行為取決於該中繼資料是否包含表單模型:
| Configuration | 行為 |
|---|---|
| 已產生的元資料可供使用。 | 驗證巢狀物件與集合,並支援訊息本地化。 |
| 產生的元資料無法提供 | 它會驗證頂層屬性,但不驗證巢狀物件或集合,也不使用 Microsoft.Extensions.Validation 訊息本地化管線。 |
| Configuration | 行為 |
|---|---|
| 已產生的元資料可供使用。 | 驗證巢狀物件與集合。 |
| 產生的元資料無法提供 | 僅驗證頂層屬性。 |
在 .NET 10 中,這些 ValidatableTypeAttributeSkipValidationAttribute API 仍處於實驗階段。 欲了解詳情及可用變通方法,請參閱 ASP.NET Core 中的驗證。
使用 Microsoft.Extensions.Validation時,請以 C# 檔案(.cs)宣告模型類型,而非 Razor 元件檔案(.razor)。 原始碼產生器會從 C# 原始碼產生驗證元資料,且無法包含元件中 Razor 宣告的模型類型。
關於組態需求、驗證順序、自訂規則、巢狀物件圖及產生的元資料,請參見 ASP.NET Core 中的驗證。
驗證巢狀物件圖
在 .NET 9 或更早版本中,會DataAnnotationsValidator驗證頂層模型屬性,但不會遞迴驗證集合型或複雜型態屬性。 對於遞迴驗證,請使用實驗性
<EditForm Model="Model" OnValidSubmit="Submit">
<ObjectGraphDataAnnotationsValidator />
...
</EditForm>
public class Starship
{
[ValidateComplexType]
public ShipDescription Description { get; set; } =
new ShipDescription();
}
該套件在這些框架版本中仍處於實驗性質。
[CompareProperty] 屬性
對於 .NET 5 或更早版本,請使用 experimental 套件的 ComparePropertyAttribute,而非 CompareAttribute。
ComparePropertyAttribute 在欄位驗證和整份表單驗證期間,都會一致地將驗證結果與欄位關聯起來。
撰寫基於模型的自訂規則
當內建屬性無法表達規則時,請使用自訂 ValidationAttribute 或 IValidatableObject。 詳細指引請參閱 ASP.NET Core 中的驗證。
撰寫基於模型的自訂規則
當內建屬性無法表達規則時,請使用 自訂的驗證屬性 或實作 IValidatableObject。 兩者都貫穿 DataAnnotationsValidator。
從自訂屬性回傳 a ValidationResult 時,請包含已驗證的成員名稱,讓結果能顯示在該欄位的 ValidationMessage 元件中。
自訂屬性可透過 GetService 解析已註冊的服務。
透過 EditContext 新增驗證
EditForm 會在其 EditContext 參數被指派時自動建立 Model。 若要直接使用驗證 API,請自行建立上下文並將其指派到 EditContext 參數 EditForm。 不要將 Model 和 EditContext 同時指派給同一個表單。
自訂驗證通常會使用:
- OnValidationRequested 用於整個表單驗證。
- OnFieldChanged 用於現場驗證。
- ValidationMessageStore 用來補充和釐清訊息。
- NotifyValidationStateChanged 在訊息變更後通知使用者介面。
以下互動式表單模式在資料註解驗證外新增表單層級商業規則,並在任一相關欄位變更時重新檢查規則:
@implements IDisposable
<EditForm EditContext="editContext" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
...
</EditForm>
@code {
private Starship Model { get; } = new Starship();
private EditContext editContext = default!;
private ValidationMessageStore messages = default!;
protected override void OnInitialized()
{
editContext = new EditContext(Model);
messages = new ValidationMessageStore(editContext);
editContext.OnValidationRequested += ValidateBusinessRules;
editContext.OnFieldChanged += ValidateChangedField;
}
private void ValidateBusinessRules(
object? sender, ValidationRequestedEventArgs e)
{
messages.Clear();
ValidateIdentifier();
editContext.NotifyValidationStateChanged();
}
private void ValidateChangedField(
object? sender, FieldChangedEventArgs e)
{
if (e.FieldIdentifier.FieldName != nameof(Starship.Identifier) &&
e.FieldIdentifier.FieldName != nameof(Starship.MaximumAccommodation))
{
return;
}
messages.Clear(
editContext.Field(nameof(Starship.Identifier)));
ValidateIdentifier();
editContext.NotifyValidationStateChanged();
}
private void ValidateIdentifier()
{
if (Model.MaximumAccommodation == 1 &&
string.IsNullOrWhiteSpace(Model.Identifier))
{
messages.Add(
editContext.Field(nameof(Starship.Identifier)),
"An identifier is required for a single-occupant ship.");
}
}
private void Submit()
{
// Process the valid form.
}
public void Dispose()
{
editContext.OnValidationRequested -= ValidateBusinessRules;
editContext.OnFieldChanged -= ValidateChangedField;
}
}
OnFieldChanged 處理常式會在 e.FieldIdentifier 中接收已變更的欄位。 清除或替換受影響的訊息並呼叫 NotifyValidationStateChanged,如前例所示。
靜態 SSR 不會在請求間提供即時的 .NET 欄位驗證。
若要進行非同步的整個表單驗證,請從 e.AddAsyncValidator 處理常式呼叫 OnValidationRequested。 若要以互動式形式進行非同步欄位驗證,請從OnFieldChanged處理器呼叫EditContext.RegisterAsyncFieldValidator。 同一欄位的新非同步驗證會取代並取消先前驗證。
關於基於模型的非同步驗證屬性,請參見 ASP.NET Core 中的驗證。 欲了解完整的可重複使用驗證器元件,請參見 ASP.NET Core Blazor 進階表單驗證。
若想了解一個可重複使用的實作,能封裝事件訂閱及其訊息庫,請參見 ASP.NET Core Blazor 進階表單驗證。
顯示驗證訊息
用於 ValidationMessage<TValue> 顯示與某一欄位相關的訊息:
<ValidationMessage For="() => Model.Identifier" />
此 For 表達式透過其模型實例與屬性來識別該欄位。
Blazor 會使用 FieldIdentifier 來表示此識別,因此,不同模型執行個體中名稱相同的屬性會被視為不同欄位。 使用表達式取代字串也讓重構工具能更新屬性參考。
用於 ValidationSummary 顯示以下表單的訊息:
<ValidationSummary />
將摘要 Model 參數指定為僅限於特定模型相關的訊息:
<ValidationSummary Model="Model" />
若要檢查程式碼中的當前訊息,請呼叫 GetValidationMessages:
var allMessages = editContext.GetValidationMessages();
var fieldMessages = editContext.GetValidationMessages(
editContext.Field(nameof(Starship.Identifier)));
這些方法讀取當前的驗證狀態。 他們不會主動提出認同。
自訂驗證外觀
Blazor 應用代表欄位與訊息狀態的 CSS 類別:
| Element | 班級 |
|---|---|
| Input |
valid 或 invalid,加上 modified 使用者編輯欄位後 |
| 驗證訊息 | validation-message |
| 驗證摘要 |
validation-summary-errors 或 validation-summary-valid |
非同步欄位驗證的輸入使用 pending 或 faulted,可選地使用 , modified代替 valid 或 invalid ,且對應狀態適用。
Blazor專案範本包含了通用且有效與無效類別的樣式。 視需要為其他類別新增樣式。
ValidationMessage 同時 ValidationSummary 也接受任意的 HTML 屬性。 提供 class 屬性會取代元件的預設類別。
要改變應用於輸入元件的類別,請從 推導出 FieldCssClassProvider。
using Microsoft.AspNetCore.Components.Forms;
public sealed class BootstrapFieldCssClassProvider : FieldCssClassProvider
{
public override string GetFieldCssClass(
EditContext editContext,
in FieldIdentifier fieldIdentifier)
{
if (!editContext.IsModified(fieldIdentifier))
{
return string.Empty;
}
return editContext.IsValid(fieldIdentifier)
? "is-valid"
: "is-invalid";
}
}
using System.Linq;
using Microsoft.AspNetCore.Components.Forms;
public sealed class BootstrapFieldCssClassProvider : FieldCssClassProvider
{
public override string GetFieldCssClass(
EditContext editContext,
in FieldIdentifier fieldIdentifier)
{
if (!editContext.IsModified(fieldIdentifier))
{
return string.Empty;
}
return editContext.GetValidationMessages(fieldIdentifier).Any()
? "is-invalid"
: "is-valid";
}
}
自訂系統 FieldCssClassProvider 會決定每個欄位的完整類別值。 若表單使用非同步欄位驗證,則在需要 pending 或 faulted 類別時,於提供者中處理 IsValidationPending(fieldIdentifier) 和 IsValidationFaulted(fieldIdentifier)。
將提供者指派至表單:EditContext
editContext.SetFieldCssClassProvider(
new BootstrapFieldCssClassProvider());
若要自訂輸入標記,請呼叫 FieldCssClass 以取得目前提供者所選的類別。
當為 EditForm 指派模型時,其子內容會接收產生的 EditContext。 透過參數 Context 捕捉上下文,並呼叫 FieldCssClass 將欄位的類別套用到周圍的標記:
<EditForm Model="Model" Context="editContext">
<DataAnnotationsValidator />
<div class="@editContext.FieldCssClass(
() => Model.Identifier)">
<InputText @bind-Value="Model.Identifier" />
<ValidationMessage For="() => Model.Identifier" />
</div>
</EditForm>
回應驗證狀態
EditContext 在不啟動驗證的情況下,暴露目前的驗證狀態。
- 使用
IsModified(field)或IsModified()來判斷表單中某欄位或任何欄位是否已變更。 - 使用
GetValidationMessages(field)或GetValidationMessages()檢查當前欄位或格式訊息。
用 IsValid(field) 來判斷欄位目前是否有驗證訊息。
對於欄位,可使用 !editContext.GetValidationMessages(field).Any() 檢查是否沒有訊息。
以下範例僅在欄位被修改且無效後才顯示自訂使用者介面:
@{
var identifier = editContext.Field(nameof(Starship.Identifier));
}
@if (editContext.IsModified(identifier) &&
!editContext.IsValid(identifier))
{
<p>Correct the identifier before continuing.</p>
}
@{
var identifier = editContext.Field(nameof(Starship.Identifier));
}
@if (editContext.IsModified(identifier) &&
editContext.GetValidationMessages(identifier).Any())
{
<p>Correct the identifier before continuing.</p>
}
輸入元件、ValidationMessage 和 ValidationSummary 會在驗證狀態變更時自行更新。 渲染其他條件驗證 UI 的元件應訂閱 OnValidationStateChanged 並呼叫 StateHasChanged:
private void HandleValidationStateChanged(
object? sender, ValidationStateChangedEventArgs e) =>
_ = InvokeAsync(StateHasChanged);
當元件遭到處置時,取消訂閱 OnValidationStateChanged。
使用 IsValidationPending(field) 與 IsValidationFaulted(field) 用於非同步欄位驗證。 不含參數的方法描述表單層級的 ValidateAsync 傳遞,且不會彙總每個欄位的狀態。
這些狀態也包括由 DataAnnotationsValidator執行的非同步工作。 套用至屬性的 AsyncValidationAttribute 會在欄位驗證期間使用欄位狀態,包括預設的 pending 和 faulted CSS 類別。 在 ValidateAsync期間,非同步屬性 和 IAsyncValidatableObject 對無參數方法報告的形式層級狀態有貢獻。
待處理的即時指示器需要互動式渲染模式。 在靜態 SSR 表單發佈時,伺服器端驗證會在回應呈現前完成。
控制表單提交
EditForm 提供三種提交回呼:
| Callback | 行為 |
|---|---|
| OnValidSubmit | 在自動驗證成功後執行。 |
| OnInvalidSubmit | 自動驗證失敗後執行。 |
| OnSubmit | 讓處理程式控制驗證和提交。 |
OnValidSubmit 且 OnInvalidSubmit 可同時使用。 不要將 OnSubmit 與它們其中任何一個結合。
EditForm在呼叫 OnValidSubmit 或 OnInvalidSubmit之前使用ValidateAsync,因此等待同步與非同步驗證者。 處理 OnSubmit 時,請先呼叫 ValidateAsync,再處理表單:
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
...
</EditForm>
@code {
private async Task HandleSubmit(EditContext editContext)
{
if (await editContext.ValidateAsync())
{
await SaveAsync();
}
}
}
Validate同步方法在 .NET 11 中已過時。 它不會等待非同步驗證,且如果處理常式嘗試註冊非同步工作,便會擲回錯誤。
對於互動式表單,可使用表單層級的待處理狀態,在 ValidateAsync 執行期間停用提交功能:
<button type="submit" disabled="@editContext.IsValidationPending()">
Save
</button>
處理 OnSubmit 時,請先呼叫 Validate,再處理表單:
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
...
</EditForm>
@code {
private void HandleSubmit(EditContext editContext)
{
if (editContext.Validate())
{
Save();
}
}
}