本文說明如何 Blazor 為使用 靜態伺服器端渲染(static SSR)的表單加入即時客戶端驗證。 瀏覽器會在使用者編輯欄位時驗證個別欄位,並在提交前驗證完整表單。 若客戶端檢查通過,表單會提交並在伺服器上再次驗證。
使用互動式渲染模式的表單並未使用本文所述的靜態 SSR 用戶端驗證功能。 他們的每個欄位驗證與完整表單提交驗證皆以 .NET 格式執行,透過表單的 EditContext。
客戶端驗證的運作方式
當靜態 SSR 表單包含 DataAnnotationsValidator 元件時,會 Blazor 將表單的驗證規則渲染到頁面中,並在表單提交前使用 JavaScript 強制執行。 使用者在不需往返伺服器的情況下會看到驗證錯誤。
當符合以下條件時,客戶端驗證會自動啟動:
- 表單的承載元件使用靜態 SSR(未對該元件套用
@rendermode指令)。 - 表單包含一個 DataAnnotationsValidator 組件。
- 表單模型使用 System.ComponentModel.DataAnnotations 驗證屬性。
對於內建的驗證屬性集合,則不需要 JavaScript 設定、額外套件或服務註冊。 「自訂用戶端驗證規則」章節說明如何新增對自訂驗證屬性的支援。
Important
客戶端驗證是提升使用者體驗,而非權威驗證通過。 可透過停用或修改瀏覽器的 JavaScript 執行來繞過此問題。 伺服器端驗證會在表單發布後執行,且保持權威性。 切勿依賴用戶端驗證來保護資料完整性。
支援的驗證屬性
以下 System.ComponentModel.DataAnnotations 屬性在用戶端強制執行,與伺服器端資料註解行為相符:
- RequiredAttribute
- StringLengthAttribute
- MinLengthAttribute
- MaxLengthAttribute
- RangeAttribute (僅當運算元類型為數字時)
- RegularExpressionAttribute
- EmailAddressAttribute
- UrlAttribute
- PhoneAttribute
- CreditCardAttribute
- CompareAttribute
- FileExtensionsAttribute
未出現在此清單中的驗證屬性,包括衍生自 ValidationAttribute 的自訂屬性,預設不會在用戶端強制執行。 表格提交後,它們仍會繼續在伺服器端運行。 若要提供自訂屬性的客戶端規則,請參閱 自訂客戶端驗證規則 章節。
驗證時序
欄位在其值被提交時即為驗證。 對於文字輸入(<input> 元素),當場域失去焦點時,就會發生這種情況。 勾選框和下拉清單會在選擇後立即驗證。
當欄位出現驗證錯誤或表單至少提交一次後,該欄位會再次按鍵驗證,以確保修正能立即反映。
提交表單即可驗證所有追蹤欄位。 若有任何欄位無效,提交將被阻擋,焦點轉移至第一個無效欄位。
驗證訊息、在地化與無障礙性
用戶端驗證用於 ValidationMessage<TValue> 顯示個別欄位的訊息,以及 ValidationSummary 整個表單的訊息,這與互動驗證向使用者回報訊息的方式相同。
設定驗證在地化後,系統會在伺服器轉譯頁面時將錯誤訊息在地化,因此用戶端驗證會顯示與伺服器端體驗一致的在地化字串。 本地化需要 Microsoft.Extensions.Validation。 欲了解更多資訊,請參閱 ASP.NET Core 中的驗證。
輸入元素與驗證訊息容器的 ARIA 屬性由 Blazor 自動管理,因此輔助技術可在無需額外設定的情況下公告驗證錯誤。
驗證狀態 CSS 類別
用戶端驗證引擎套用與 Blazor互動式驗證相同的 CSS 類別,如下表所示。
| Element | 班級 |
|---|---|
| Input |
valid 或 invalid,加上 modified 使用者編輯欄位後 |
| 驗證訊息 | validation-message |
| 驗證摘要 |
validation-summary-errors 或 validation-summary-valid |
用戶端驗證也會呼叫瀏覽器的 Constraint Validation API,因此標準的 CSS 偽類別 :valid 和 :invalid 會反映每個輸入欄位目前的驗證狀態。
選擇退出用戶端驗證
此功能可在多個層級關閉。 伺服器端驗證不受本節選項影響。
選擇不使用單一表格
將元件參數DisableClientValidation設DataAnnotationsValidator為true:
<DataAnnotationsValidator DisableClientValidation="true" />
選擇退出整個應用程式
當Razor元件服務已在Program檔案中註冊時,於RazorComponentsServiceOptions上設定DisableClientValidation:
builder.Services.AddRazorComponents(options =>
{
options.DisableClientValidation = true;
});
全球選項優先。 當它設為 true時,表單不會發出客戶端驗證規則。
停用單一送出按鈕設定
請使用按鈕上的標準 HTML formnovalidate 屬性 。 表單發布時未進行客戶端檢查,伺服器端驗證仍會在貼文後執行:
<button type="submit" formnovalidate>Save draft</button>
這可以用來實現「儲存草稿」或「返回」按鈕,且不需要完全有效的表單才能成功提交。
自訂客戶端驗證規則
自訂驗證屬性會持續在伺服器上執行,但預設沒有客戶端實作。 在瀏覽器中強制執行自訂規則包含兩個步驟:從 .NET 屬性發出規則,以及註冊一個匹配的 JavaScript 驗證器。 伺服器端的實作仍具權威性。
從 .NET 發出規則
在驗證屬性上實作 IClientValidationRuleProvider 並回傳一個或多個 ClientValidationRule 實例。 規則 Name 會識別客戶端驗證者,並提供 Parameters 驗證者所需的值。
以下 StartsWithAttribute 會在 IsValid 中於伺服器端驗證,並提供一個含有 prefix 參數的 startswith 用戶端規則:
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components.Forms;
namespace BlazorSample.Validation;
// A custom validation attribute that also contributes a client-side rule for static SSR
// forms. The rule name ('startswith') must match the validator registered on the client
// with Blazor.formValidation.addValidator.
public sealed class StartsWithAttribute : ValidationAttribute, IClientValidationRuleProvider
{
private readonly string prefix;
public StartsWithAttribute(string prefix)
{
this.prefix = prefix;
ErrorMessage = $"The value must start with '{prefix}'.";
}
protected override ValidationResult? IsValid(object? value,
ValidationContext validationContext)
{
// Leave empty values to RequiredAttribute, matching the client-side validator.
if (value is not string text || text.Length == 0)
{
return ValidationResult.Success;
}
if (!text.StartsWith(prefix, StringComparison.Ordinal))
{
return new ValidationResult(ErrorMessage, [validationContext.MemberName!]);
}
return ValidationResult.Success;
}
public IEnumerable<ClientValidationRule> GetClientValidationRules()
{
yield return new ClientValidationRule(
"startswith",
new Dictionary<string, string> { ["prefix"] = prefix });
}
}
以通常方式將屬性套用到模型上:
using System.ComponentModel.DataAnnotations;
namespace BlazorSample.Validation;
// Model for the static SSR client-side validation sample. The StartsWith attribute
// contributes a client-side rule enforced in the browser before the form is submitted.
public class ShipModel
{
[Required]
[StartsWith("NCC-")]
public string? Registry { get; set; }
}
註冊 JavaScript 驗證器
在 JavaScript 中,呼叫 Blazor.formValidation.addValidator(name, validator) 將規則名稱與驗證器函式關聯。
name必須完全匹配ClientValidationRule.Name,包括外殼。 註冊是整個應用程式的,再次註冊相同名稱會取代先前的驗證者。
Warning
若未註冊 JavaScript 驗證器以處理已發出的規則名稱,則該規則在瀏覽器中會被跳過。 伺服器端驗證在表單發布時仍會執行。
從應用程式啟動程式碼註冊一次自訂驗證器。 根據下表所述,依照 Blazor 的啟動方式選擇註冊位置。
| Blazor 新創公司 | 註冊地點 |
|---|---|
| 自動啟動(預設) | 緊接在 blazor.web.js 之後的指令碼 |
手動 Blazor.start() |
由 Blazor.start() 傳回的接續 |
| 任一種啟動樣式 | JavaScript 初始化器的 afterWebStarted 回調 |
JavaScript 初始化器可使用任一種啟動風格。 在應用程式的 {ASSEMBLY NAME}.lib.module.js 資料夾中名為 wwwroot 的檔案內:
// A JavaScript initializer works with automatic or manual Blazor startup. The validation service
// is available when afterWebStarted runs, even if the current page contains no validated form.
export function afterWebStarted(blazor) {
blazor.formValidation.addValidator('startswith', (context) => {
const value = context.value;
// An empty value is valid. Use [Required] to require a value.
if (!value) {
return { success: true };
}
return { success: value.startsWith(context.params.prefix) };
});
}
透過自動啟動,可以在 blazor.web.js 之後立即載入應用程式專用的驗證指令碼:
<script src="@Assets["_framework/blazor.web.js"]"></script>
<script src="@Assets["js/custom-validation.js"]"></script>
第二個腳本可以直接呼叫 Blazor.formValidation.addValidator 。
手動啟動時,請在應用程式腳本中定義註冊:
function registerCustomValidators(blazor) {
blazor.formValidation.addValidator('startswith', (context) => {
const value = context.value;
if (!value) {
return { success: true };
}
return { success: value.startsWith(context.params.prefix) };
});
}
// Automatic startup initializes formValidation before this script runs.
// Manual startup calls registerCustomValidators after Blazor.start completes.
if (Blazor.formValidation) {
registerCustomValidators(Blazor);
}
載入已停用自動啟動的指令碼,並在 Blazor.start() 完成後註冊驗證器:
<script src="@Assets["_framework/blazor.web.js"]" autostart="false"></script>
<script src="@Assets["js/custom-validation.js"]"></script>
<script>
Blazor.start().then(() => {
registerCustomValidators(Blazor);
});
</script>
Important
從應用程式啟動程式碼註冊驗證器,而非從頁面或表單元件註冊。 元件指令碼可以在 Blazor 啟動之前執行,而透過增強型導覽新增的指令碼不會執行。 靜態 SSR 元件也無法使用IJSRuntime,因為它們沒有互動式的 .NET 執行環境。
撰寫 JavaScript 驗證函式
驗證者會收到包含以下成員的上下文物件,如下表所示。
| 會員 | 描述 |
|---|---|
value |
欄位目前的值(以字串表示),若沒有值則為 null/undefined。 |
element |
驗證的 input、 select或 textarea 元素。 |
params |
規則就像 Parameters 字典一樣。 |
驗證者預期在值有效時回傳 { success: true } 。 傳回 { success: false } 以使用該規則的伺服器提供訊息,或者您也可以傳回 { success: false, message: '...' } 以覆寫該次呼叫的訊息。
空值通常應被除 required之外的規則視為有效,允許選填欄位保持空置,同時仍能驗證所提供的值。
在 .NET 和 JavaScript 中實作相同的規則語意,包括大小寫敏感性、正規化和空值處理。 若實作不同,瀏覽器與權威伺服器端驗證可能會產生不同結果。
按需驗證表單
API Blazor.formValidation 也暴露了用於按需驗證的 JavaScript 方法,如下表所示。
| 方法 | 描述 |
|---|---|
validateField(element) |
驗證單一欄位元素並更新其錯誤顯示。 有效時會傳回 true。 |
validateForm(form) |
驗證表單中所有追蹤欄位。 當所有欄位都有效時回傳 true 。 |
Limitations
- 用戶端規則僅針對伺服器端驗證中包含的欄位會產生。 若無 Microsoft.Extensions.Validation,則僅驗證頂層模型屬性。 驗證巢狀物件與集合需要應用程式呼叫 AddValidation 並發現模型。 欲了解更多資訊,請參閱 ASP.NET Core 中的驗證。 請注意,此限制是刻意設計的,目的是防止因設定錯誤而導致權威伺服器驗證缺失的錯誤。
- 透過後續 串流渲染 更新新增的輸入,不會獲得客戶端驗證。 單批次交付的表單通常會被覆蓋。
- 只有 支援的驗證屬性 中列出的屬性具有內建的用戶端實作。 例如,非數值運算元型別的 a RangeAttribute 只會在伺服器端強制執行。 其他屬性則需要自訂的 客戶端驗證規則。
- 自訂 JavaScript 驗證器是同步式的。 需要網路呼叫或其他非同步運算的規則必須在伺服器上執行,或使用帶有互動式渲染模式的非同步驗證。 欲了解更多資訊,請參閱 ASP.NET Core Blazor 進階表單驗證。