共用方式為


ASP.NET Core Blazor 表單概觀

注意

這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前的版本,請參閱 本文的 .NET 9 版本。

本文說明如何在 Blazor 中使用表單。

輸入元件和表單

Blazor 架構支援表單並提供內建的輸入元件:

注意

不支援的驗證功能一節說明不支援的 ASP.NET Core 驗證功能。

Microsoft.AspNetCore.Components.Forms 命名空間提供:

  • 用於管理表單元素、狀態和驗證的類別。
  • 內建 Input* 元件的存取權。

從 Blazor 專案範本建立的專案在應用程式的 _Imports.razor 檔案中包含命名空間,其會讓命名空間可供應用程式的 Razor 元件使用。

支援標準 HTML 表單。 使用一般 HTML <form> 標記來建立表單,並指定 @onsubmit 處理常式來處理提交的表單要求。

StarshipPlainForm.razor

@page "/starship-plain-form"
@inject ILogger<StarshipPlainForm> Logger

<form method="post" @onsubmit="Submit" @formname="starship-plain-form">
    <AntiforgeryToken />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}
@page "/starship-plain-form"
@inject ILogger<StarshipPlainForm> Logger

<form method="post" @onsubmit="Submit" @formname="starship-plain-form">
    <AntiforgeryToken />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}

在上述 StarshipPlainForm 元件中:

  • 表單會在 <form> 元素出現的位置轉譯。 表單是以 @formname 指示詞屬性命名,該屬性會對 Blazor 架構唯一識別該表單。
  • 模型會在元件的 @code 區塊中建立,並保留在公用屬性 (Model) 中。 [SupplyParameterFromForm] 屬性會指出應該從表單資料提供相關聯屬性的值。 要求中符合屬性名稱的資料會繫結至屬性。
  • InputText 元件是用於編輯字串值的輸入元件。 @bind-Value 指示詞屬性會將 Model.Id 模型屬性繫結至 InputText 元件的 Value 屬性。
  • Submit 方法會註冊為 @onsubmit 回撥的處理常式。 當使用者提交表單時,會呼叫處理常式。

重要

請一律使用具有唯一表單名稱的 @formname 指示詞屬性。

Blazor 會藉由攔截要求以將回應套用至現有的 DOM,盡可能保留轉譯的表單,藉此增強頁面導覽和表單處理。 增強功能可避免需要完整載入頁面,並提供更順暢的使用者體驗,類似於單頁應用程式 (SPA),不過元件會在伺服器上轉譯。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和導覽

針對純文字 HTML 表單支援串流轉譯

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

上述範例透過在表單中包含 AntiforgeryToken 元件,包括防偽支援。 本文的防偽支援一節會進一步說明防偽支援。

若要根據另一個元素的 DOM 事件提交表單,例如 oninputonblur,請使用 JavaScript 來提交表單 (submit (MDN 文件))。

並非在 Blazor 應用程式中使用純文字表單,表單通常會以使用架構 EditForm 元件的 Blazor 內建表單支援來定義。 下列 Razor 元件示範一般元素、元件和 Razor 程式碼,以使用 EditForm 元件轉譯 Webform。

表單是使用 Blazor 架構的 EditForm 元件來定義。 下列 Razor 元件示範一般元素、元件和 Razor 程式碼,以使用 EditForm 元件轉譯 Webform。

Starship1.razor

@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship1">
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}
@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship1">
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}

在上述 Starship1 元件中:

  • EditForm 元件會在 <EditForm> 元素出現的位置轉譯。 表單是以 @formname 指示詞屬性命名,該屬性會對 Blazor 架構唯一識別該表單。
  • 模型會在元件的 @code 區塊中建立,並保留在公用屬性 (Model) 中。 屬性指派給 EditForm.Model 參數。 [SupplyParameterFromForm] 屬性會指出應該從表單資料提供相關聯屬性的值。 要求中符合屬性名稱的資料會繫結至屬性。
  • InputText 元件是用於編輯字串值的輸入元件@bind-Value 指示詞屬性會將 Model.Id 模型屬性繫結至 InputText 元件的 Value 屬性。
  • Submit 方法會註冊為 OnSubmit 回撥的處理常式。 當使用者提交表單時,會呼叫處理常式。

重要

請一律使用具有唯一表單名稱的 @formname 指示詞屬性。

Blazor 會增強 EditForm 元件的頁面導覽和表單處理。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽

針對 EditForm 支援串流轉譯

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit">
    <InputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit()
    {
        Logger.LogInformation("Model.Id = {Id}", Model?.Id);
    }

    public class Starship
    {
        public string? Id { get; set; }
    }
}

在上述 Starship1 元件中:

  • EditForm 元件會在 <EditForm> 元素出現的位置轉譯。
  • 模型會在元件的 @code 區塊中建立,並保留在私人欄位 (model) 中。 欄位會指派給 EditForm.Model 參數。
  • InputText 元件是用於編輯字串值的輸入元件。 @bind-Value 指示詞屬性會將 Model.Id 模型屬性繫結至 InputText 元件的 Value 屬性†。
  • Submit 方法會註冊為 OnSubmit 回撥的處理常式。 當使用者提交表單時,會呼叫處理常式。

†如需屬性繫結的詳細資訊,請參閱 ASP.NET Core Blazor 資料繫結

在下一個範例中,會修改上述元件,以在 Starship2 元件中建立表單:

  • OnSubmit 會取代為 OnValidSubmit,如果使用者提交表單時表單有效,則會處理指派的事件處理常式。
  • 新增 ValidationSummary 元件以在表單於提交表單時無效時顯示驗證訊息。
  • 資料註釋驗證程式 (DataAnnotationsValidator 元件†) 會使用資料註釋附加驗證支援:
    • 如果選取 <input> 按鈕時,Submit 表單欄位保留空白,則驗證摘要 (ValidationSummary元件 ‡) ("The Id field is required.") 中會出現錯誤,且不會呼叫 Submit
    • 如果選取 Submit 按鈕時,<input> 表單欄位包含超過十個字元,驗證摘要中會出現錯誤 ("Id is too long.")。 不會呼叫 Submit
    • 如果 <input> 表單欄位在選取 Submit 按鈕時包含有效的值,則會呼叫 Submit

驗證程式元件一節說明 DataAnnotationsValidator 元件。 ‡驗證摘要和驗證訊息元件一節說明 ValidationSummary 元件。

Starship2.razor

@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship2">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <label>
        Identifier: 
        <InputText @bind-Value="Model!.Id" />
    </label>
    <button type="submit">Submit</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship2">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <label>
        Identifier: 
        <InputText @bind-Value="Model!.Id" />
    </label>
    <button type="submit">Submit</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit()
    {
        Logger.LogInformation("Id = {Id}", Model?.Id);
    }

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}

處理表單提交

EditForm 提供下列回撥來處理表單提交:

  • 使用 OnValidSubmit 來指派事件處理常式,以在提交具有有效欄位的表單時執行。
  • 使用 OnInvalidSubmit 來指派事件處理常式,以在提交具有無效欄位的表單時執行。
  • 使用 OnSubmit 來指派事件處理常式,以在不論表單欄位的驗證狀態為何時執行。 驗證表單的方式是在事件處理常式方法中呼叫 EditContext.Validate。 如果 Validate 傳回 true,則表單有效。

清除表單或欄位

藉由將模型清除回其預設狀態以重設表單,此動作可在 EditForm 的標記內部或外部執行:

<button @onclick="ClearForm">Clear form</button>

...

private void ClearForm() => Model = new();

或者,使用明確的 Razor 運算式:

<button @onclick="@(() => Model = new())">Clear form</button>

將模型值清除回預設狀態,以重設欄位:

<button @onclick="ResetId">Reset Identifier</button>

...

private void ResetId() => Model!.Id = string.Empty;

或者,使用明確的 Razor 運算式:

<button @onclick="@(() => Model!.Id = string.Empty)">Reset Identifier</button>

在上述範例中不需要呼叫 StateHasChanged,因為 Blazor 架構會自動呼叫 StateHasChanged,以在叫用事件處理常式之後重新轉譯元件。 如果未使用事件處理常式來叫用可清除表單或欄位的方法,則開發人員程式碼應該呼叫 StateHasChanged 以重新轉譯元件。

防偽造支援

AddRazorComponentsProgram 檔案中進行呼叫時,防偽服務會自動新增至 Blazor 應用程式。

應用程式會藉由在 Program 檔案中於其要求處理管線呼叫 UseAntiforgery,使用防偽中介軟體。 在呼叫 UseRouting 之後呼叫 UseAntiforgery。 如果有對 UseRoutingUseEndpoints 發出呼叫,則對 UseAntiforgery 的呼叫必須介於這兩者之間。 對 UseAntiforgery 發出的呼叫必須在放置對 UseAuthenticationUseAuthorization 發出的呼叫之後。

AntiforgeryToken 元件會將防偽造權杖轉譯為隱藏欄位,而 [RequireAntiforgeryToken] 屬性會啟用防偽造保護。 如果防偽造檢查失敗,則會擲出 400 - Bad Request 回應,而且不會處理表單。

針對以 EditForm 為基礎的表單,AntiforgeryToken 元件與 [RequireAntiforgeryToken] 屬性會自動新增,以提供防偽造保護。

針對以 HTML <form> 元素為基礎的表單,請手動將 AntiforgeryToken 元件新增至表單:

<form method="post" @onsubmit="Submit" @formname="starshipForm">
    <AntiforgeryToken />
    <input id="send" type="submit" value="Send" />
</form>

@if (submitted)
{
    <p>Form submitted!</p>
}

@code{
    private bool submitted = false;

    private void Submit() => submitted = true;
}

警告

針對以 EditForm 或 HTML <form> 元素為基礎的表單,可以藉由傳遞 required: false[RequireAntiforgeryToken] 屬性來停用防偽造保護。 下列範例會停用防偽造,且不建議用於公用應用程式:

@using Microsoft.AspNetCore.Antiforgery
@attribute [RequireAntiforgeryToken(required: false)]

如需詳細資訊,請參閱 ASP.NET Core Blazor 驗證和授權

減輕過度發佈攻擊

靜態呈現的伺服器端表單 (例如,通常在使用表單模型在資料庫中建立和編輯記錄的元件中使用的表單) 可能容易受到過度發佈攻擊 (也稱為大規模指派攻擊)。 當惡意使用者向伺服器發出 HTML 表單 POST 要求,該伺服器處理不屬於所呈現表單的屬性的資料且開發人員不希望允許使用者修改該屬性時,就會發生過度發佈攻擊。 「過度發佈」一詞的字面意思是惡意使用者已過度發佈表單。

當模型不包含建立和更新作業的受限屬性時,過度發佈就不是一個要擔心的問題。 不過,在使用您所維護的靜態 SSR 型 Blazor 表單時,請務必記住過度發佈。

為了減少過度發佈,我們建議使用個別的檢視模型/資料傳輸物件 (DTO) 來進行表單和資料庫的建立 (插入) 和更新作業。 提交表單時,元件和 C# 程式碼只會使用檢視模型/DTO 的屬性來修改資料庫。 惡意使用者所包含的任何額外資料都會被捨棄,因此可以防止惡意使用者進行過度發佈攻擊。

增強式表單處理

表單 POST 要求的增強式導覽,搭配 Enhance 參數用於 EditForm 表單,或 data-enhance 參數用於 HTML 表單 (<form>):

<EditForm ... Enhance ...>
    ...
</EditForm>
<form ... data-enhance ...>
    ...
</form>

不支援:您無法在表單的上階元素上設定增強式導覽,以啟用增強式表單處理。

<div ... data-enhance ...>
    <form ...>
        <!-- NOT enhanced -->
    </form>
</div>

增強式表單貼文僅適用 Blazor 端點。 將增強式表單張貼至非 Blazor 端點會導致錯誤。

若要停用增強式表單處理:

  • 針對 EditForm,請從表單元素移除 Enhance 參數 (或將其設定為 falseEnhance="false")。
  • 針對 HTML <form>,請從表單元素移除 data-enhance 屬性 (或將其設定為 falsedata-enhance="false")。

如果更新的內容不屬於伺服器轉譯的一部分,Blazor 的增強式導覽和表單遞交可能會復原對 DOM 的動態變更。 若要保留元素的內容,請使用 data-permanent 屬性。

在下列範例中,當頁面載入時,指令碼會動態更新 <div> 元素的內容:

<div data-permanent>
    ...
</div>

若要全域停用增強式導覽和表單處理,請參閱 ASP.NET Core Blazor 啟動

如需使用 enhancedload 事件來接聽增強版頁面更新的指導,請參閱 ASP.NET Core Blazor路由和導覽

範例

範例並未針對表單 POST 要求採用增強式表單處理,但所有範例都可以更新以採用增強式功能,方法是遵循增強式表單處理一節中的指導。

範例會使用隨著 C# 9.0 和 .NET 5 引進的目標型別 new 運算子。 在下列範例中,未明確陳述 new 運算子的型別:

public ShipDescription ShipDescription { get; set; } = new();

如果使用 C# 8.0 或更早版本 (ASP.NET Core 3.1),請修改範例程式碼,以將型別陳述為 new 運算子:

public ShipDescription ShipDescription { get; set; } = new ShipDescription();

元件會使用可為 Null 的參考型別 (NRT),而 .NET 編譯器會執行 Null 狀態靜態分析,這兩者在 .NET 6 或更新版本中都可支援。 如需詳細資訊,請參閱從 ASP.NET Core 5.0 移轉至 6.0

如果使用 C# 9.0 或更早版本 (.NET 5 或更早版本),請從範例中移除 NRT。 通常,這只牽涉到從範例程式碼中的型別中移除問號 (?) 和驚嘆號 (!)。

以 .NET 6 或更新版本為目標時,.NET SDK 會將隱含全域 using 指示詞套用至專案。 範例會使用記錄器來記錄表單處理的相關資訊,但不需要在元件範例中為 Microsoft.Extensions.Logging 命名空間指定 @using 指示詞。 如需詳細資訊,請參閱 .NET 專案 SDK:隱含 using 指示詞

如果使用 C# 9.0 或更早版本 (.NET 5 或更早版本),請針對範例要求的任何 API,將 @using 指示詞新增至元件頂端的 @page 指示詞之後。 透過 Visual Studio (以滑鼠右鍵按一下物件,然後選取 [查看定義]) 或 .NET API 瀏覽器尋找 API 命名空間。

為了示範表單如何搭配資料註釋驗證使用,範例元件會依賴 System.ComponentModel.DataAnnotations API。 如果您想要避免在使用資料註釋的元件中使用額外的程式碼,請使用匯入檔案 (_Imports.razor) 讓命名空間可供整個應用程式的元件使用:

@using System.ComponentModel.DataAnnotations

表單範例會參考 Star Trek 宇宙的層面。 Star Trek 的著作權屬於 CBS StudiosParamount ©1966-2023。

用戶端驗證需要線路

在 Blazor Web App 中,用戶端驗證需要使用中的 BlazorSignalR 線路。 用戶端驗證不適用於已採用靜態伺服器端轉譯 (靜態 SSR) 的元件中的表單。 採用靜態 SSR 的表單在提交表單後會在伺服器上進行驗證。

不支援的驗證功能

Blazor 中支援所有資料註釋內建驗證程式[Remote] 驗證屬性除外。

元件不支援 jQuery 驗證 Razor 。 我們建議使用下列任一種方法:

  • 請遵循 ASP.NET Core Blazor 窗體驗證中的指引,以取得下列其中一項:
    • 採用互動式轉譯模式的 Blazor Web App 伺服器端驗證。
    • 獨立 Blazor Web 元件應用程式中的客戶端驗證。
  • 使用原生 HTML 驗證屬性(請參閱用戶端窗體驗證(MDN 檔))。
  • 採用第三方驗證 JavaScript 連結庫。

針對伺服器上的靜態轉譯窗體,客戶端驗證的新機制會在 2025 年底考慮 .NET 10。 如需詳細資訊,請參閱在沒有線路的情況下使用 建立具有客戶端驗證的伺服器Blazor轉譯表單 (dotnet/aspnetcore#51040)。

其他資源