ASP.NET Core Blazor表单概述

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅此文的 .NET 8 版本

本文介绍如何使用 Blazor 中的窗体。

输入组件和窗体

Blazor 框架支持窗体并提供内置输入组件:

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]
    public 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 文档])。

使用框架的EditForm组件,通常使用Blazor的内置表单支持以定义表单,而不是在Blazor应用中使用纯表单。 以下 Razor 组件演示了使用 EditForm 组件来呈现 WebForm 的典型元素、组件和 Razor 代码。

窗体是使用 Blazor 框架的 EditForm 组件进行定义的。 以下 Razor 组件演示了使用 EditForm 组件来呈现 WebForm 的典型元素、组件和 Razor 代码。

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]
    public 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 组件†)使用数据注释附加验证支持:
    • 如果在选择 Submit 按钮时 <input> 表单域为空,则验证摘要(ValidationSummary 组件‡)(“The Id field is required.”)会显示错误,并且系统不会调用 Submit
    • 如果在选择 Submit 按钮时 <input> 窗体字段包含超过十个字符,则验证摘要中显示错误 ("Id is too long.")。 未调用 Submit
    • 如果在选择 Submit 按钮时 <input> 表单域包含有效的值,则系统会调用 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]
    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; }
    }
}
@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 来重新呈现组件。

防伪支持

Program 文件中调用 AddRazorComponents 时,会自动将防伪服务添加到 Blazor 应用。

应用通过在 Program 文件中的处理管道请求中调用 UseAntiforgery 来使用防伪中间件。 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 身份验证和授权

增强型表单处理

EditForm表单的Enhance参数或 HTML 表单 (<form>) 的data-enhance特性对表单 POST 请求采用增强型导航

<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();

组件使用可空引用类型 (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 的 @page 指令之后,将 @using 指令添加到组件顶部。 通过 Visual Studio(右键单击对象并选择“速览定义”)或 .NET API 浏览器查找 API 命名空间。

为了演示窗体如何用于数据注释验证,示例组件依赖于 System.ComponentModel.DataAnnotations API。 如果希望避免在使用数据注释的组件中使用额外代码行,请在整个应用的组件中使用导入文件(_Imports.razor)提供命名空间:

@using System.ComponentModel.DataAnnotations

窗体示例引用 Star Trek(星际迷航)世界的各个方面。 Star Trek(星际迷航)是 CBS StudiosParamount 的版权 ©1966-2023。

其他资源