共用方式為


ASP.NET Core Blazor 表單總覽

注意

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

警告

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

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 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 表單支援串流轉譯。 請注意,當POST表單時,只有表單處理器內的 DOM 更新會被串流傳輸(例如@onsubmit)。 只有針對OnInitializedAsync要求,內部GET的更新才會進行串流處理。 如需詳細資訊,請參閱 允許串流 POST 回應的載入階段 (dotnet/aspnetcore #50994)

注意

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

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

若要根據另一個專案的 DOM 事件提交表單,例如 oninputonblur,請使用 JavaScript 提交表單 (submit)。

在 Blazor 應用程式中,通常表單不是使用簡單表單,而是透過框架的 Blazor 元件提供的 EditForm 內建表單支援來定義。 下列 Razor 元件示範典型的元素、元件和 Razor 程式碼,來使用 EditForm 元件呈現網頁表單。

表單是使用 Blazor 架構的 EditForm 元件來定義。 下列 Razor 元件示範典型的元素、元件和 Razor 程式碼,來使用 EditForm 元件呈現網頁表單。

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 路由和導覽

針對 支援串流渲染功能。 請注意,當POST表單時,只有表單處理器內的 DOM 更新會被串流傳輸(例如OnValidSubmit)。 只有針對OnInitializedAsync要求,內部GET的更新才會進行串流處理。 如需詳細資訊,請參閱 允許串流 POST 回應的載入階段 (dotnet/aspnetcore #50994)

注意

.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
    • 如果選取 <input> 按鈕時,Submit 表單欄位包含超過十個字元,驗證摘要中會出現錯誤 ("Id is too long.")。 Submit未呼叫
    • 如果 <input> 表單欄位在選取 Submit 按鈕時包含有效的值,則會呼叫 Submit

DataAnnotationsValidator 元件在 Validator 元件 一節中介紹。 ‡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,因為 StateHasChanged 架構會自動呼叫 Blazor,以在叫用事件處理常式之後重新轉譯元件。 如果未使用事件處理常式來叫用可清除表單或欄位的方法,則開發人員程式碼應該呼叫 StateHasChanged 以重新轉譯元件。

防偽造支援

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

應用程式在 UseAntiforgery 檔案中的要求處理管線中呼叫 Program,以使用防偽中介軟體。 在呼叫 UseAntiforgery 之前,會先呼叫 UseRouting。 如果有對 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 和 .NET 5 中引入的 目標型別運算符new。 在下列範例中,未明確陳述 new 運算子的型別:

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

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

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

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

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

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

如果使用 C# 9 或更早版本(.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除外。

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

  • 請遵循 Blazor中的指引,來執行下列其中一項:
    • 採用互動式轉譯模式的 Blazor Web App 伺服器端驗證。
    • 獨立 Blazor WebAssembly 應用程式中的用戶端驗證。
  • 使用原生 HTML 驗證屬性(請參閱 客戶端表單驗證)。
  • 採用第三方驗證 JavaScript 函式庫。

針對伺服器上的靜態渲染表單,正在考慮的客戶端驗證新機制預計在 2025 年底引入 .NET 10。 如需詳細資訊,請參閱使用Blazor建立由伺服器渲染,並具有客戶端驗證的表單,此無需流程(dotnet/aspnetcore#51040)。

其他資源