ASP.NET Core 表单中的标记帮助程序Tag Helpers in forms in ASP.NET Core

作者:Rick AndersonN. Taylor MullenDave PaquetteJerrie PelserBy Rick Anderson, N. Taylor Mullen, Dave Paquette, and Jerrie Pelser

本文档演示如何使用表单和表单中常用的 HTML 元素。This document demonstrates working with Forms and the HTML elements commonly used on a Form. HTML Form 元素提供 Web 应用用于向服务器回发数据的主要机制。The HTML Form element provides the primary mechanism web apps use to post back data to the server. 本文档的大部分内容介绍标记帮助程序及其如何帮助高效创建可靠的 HTML 表单。Most of this document describes Tag Helpers and how they can help you productively create robust HTML forms. 建议在阅读本文档前先阅读标记帮助程序简介We recommend you read Introduction to Tag Helpers before you read this document.

在很多情况下,HTML 帮助程序为特定标记帮助程序提供了一种替代方法,但标记帮助程序不会替代 HTML 帮助程序,且并非每个 HTML 帮助程序都有对应的标记帮助程序,认识到这点也很重要。In many cases, HTML Helpers provide an alternative approach to a specific Tag Helper, but it's important to recognize that Tag Helpers don't replace HTML Helpers and there's not a Tag Helper for each HTML Helper. 如果存在 HTML 帮助程序替代项,文中会提到。When an HTML Helper alternative exists, it's mentioned.

表单标记帮助程序The Form Tag Helper

表单标记帮助程序:The Form Tag Helper:

  • 为 MVC 控制器操作或命名路由生成 HTML <FORM> action 属性值Generates the HTML <FORM> action attribute value for a MVC controller action or named route

  • 生成隐藏的请求验证令牌,防止跨站点请求伪造(在 HTTP Post 操作方法中与 [ValidateAntiForgeryToken] 属性配合使用时)Generates a hidden Request Verification Token to prevent cross-site request forgery (when used with the [ValidateAntiForgeryToken] attribute in the HTTP Post action method)

  • 提供 asp-route-<Parameter Name> 属性,其中 <Parameter Name> 添加到路由值。Provides the asp-route-<Parameter Name> attribute, where <Parameter Name> is added to the route values. Html.BeginFormHtml.BeginRouteFormrouteValues 参数提供类似的功能。The routeValues parameters to Html.BeginForm and Html.BeginRouteForm provide similar functionality.

  • 具有 HTML 帮助程序替代项 Html.BeginFormHtml.BeginRouteFormHas an HTML Helper alternative Html.BeginForm and Html.BeginRouteForm

示例:Sample:

<form asp-controller="Demo" asp-action="Register" method="post">
    <!-- Input and Submit elements -->
</form>

上述表单标记帮助程序生成以下 HTML:The Form Tag Helper above generates the following HTML:

<form method="post" action="/Demo/Register">
    <!-- Input and Submit elements -->
    <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

MVC 运行时通过表单标记帮助程序属性 asp-controllerasp-action 生成 action 属性值。The MVC runtime generates the action attribute value from the Form Tag Helper attributes asp-controller and asp-action. 表单标记帮助程序还会生成隐藏的请求验证令牌,防止跨站点请求伪造(在 HTTP Post 操作方法中与 [ValidateAntiForgeryToken] 属性配合使用时)。The Form Tag Helper also generates a hidden Request Verification Token to prevent cross-site request forgery (when used with the [ValidateAntiForgeryToken] attribute in the HTTP Post action method). 保护纯 HTML 表单免受跨站点请求伪造的影响很难,但表单标记帮助程序可提供此服务。Protecting a pure HTML Form from cross-site request forgery is difficult, the Form Tag Helper provides this service for you.

使用命名路由Using a named route

asp-route 标记帮助程序属性还可为 HTML action 属性生成标记。The asp-route Tag Helper attribute can also generate markup for the HTML action attribute. 具有名为 register路由的应用可将以下标记用于注册页:An app with a route named register could use the following markup for the registration page:

<form asp-route="register" method="post">
    <!-- Input and Submit elements -->
</form>

Views/Account 文件夹中的许多视图(在新建使用个人用户帐户身份验证的 Web 应用时生成)包含 asp-route-returnurl 属性:Many of the views in the Views/Account folder (generated when you create a new web app with Individual User Accounts) contain the asp-route-returnurl attribute:

<form asp-controller="Account" asp-action="Login"
     asp-route-returnurl="@ViewData["ReturnUrl"]"
     method="post" class="form-horizontal" role="form">

备注

使用内置模板时,returnUrl 仅会在用户尝试访问授权资源,但未验证身份或未获得授权的情况下自动填充。With the built in templates, returnUrl is only populated automatically when you try to access an authorized resource but are not authenticated or authorized. 如果尝试执行未经授权的访问,安全中间件会使用 returnUrl 集将用户重定向至登录页。When you attempt an unauthorized access, the security middleware redirects you to the login page with the returnUrl set.

窗体操作标记帮助程序The Form Action Tag Helper

窗体操作标记帮助程序在生成的 <button ...><input type="image" ...> 标记上生成 formaction 属性。The Form Action Tag Helper generates the formaction attribute on the generated <button ...> or <input type="image" ...> tag. formaction 属性控制窗体在何处提交数据。The formaction attribute controls where a form submits its data. 它绑定到 image 类型的 <input> 元素以及 <button> 元素。It binds to <input> elements of type image and <button> elements. 窗体操作标记帮助程序允许使用多个 AnchorTagHelperasp- 属性来控制为相应元素生成的 formaction 链接。The Form Action Tag Helper enables the usage of several AnchorTagHelper asp- attributes to control what formaction link is generated for the corresponding element.

用于控制 formaction 值的受支持的 AnchorTagHelper 属性:Supported AnchorTagHelper attributes to control the value of formaction:

特性Attribute 说明Description
asp-controllerasp-controller 控制器的名称。The name of the controller.
asp-actionasp-action 操作方法的名称。The name of the action method.
asp-areaasp-area 区域名称。The name of the area.
asp-pageasp-page Razor Page 的名称。The name of the Razor page.
asp-page-handlerasp-page-handler Razor Page 处理程序的名称。The name of the Razor page handler.
asp-routeasp-route 路由的名称。The name of the route.
asp-route-{value}asp-route-{value} 单个 URL 路由值。A single URL route value. 例如 asp-route-id="1234"For example, asp-route-id="1234".
asp-all-route-dataasp-all-route-data 所有路由值。All route values.
asp-fragmentasp-fragment URL 片段。The URL fragment.

提交到控制器示例Submit to controller example

选中输入或按钮时,下面的标记将窗体提交到 HomeControllerIndex 操作:The following markup submits the form to the Index action of HomeController when the input or button are selected:

<form method="post">
    <button asp-controller="Home" asp-action="Index">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-controller="Home" 
                                asp-action="Index">
</form>

之前的标记将生成以下 HTML:The previous markup generates following HTML:

<form method="post">
    <button formaction="/Home">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/Home">
</form>

提交到页示例Submit to page example

以下标记将窗体提交到 About Razor Page:The following markup submits the form to the About Razor Page:

<form method="post">
    <button asp-page="About">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-page="About">
</form>

之前的标记将生成以下 HTML:The previous markup generates following HTML:

<form method="post">
    <button formaction="/About">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/About">
</form>

提交到路由示例Submit to route example

请考虑使用 /Home/Test 终结点:Consider the /Home/Test endpoint:

public class HomeController : Controller
{
    [Route("/Home/Test", Name = "Custom")]
    public string Test()
    {
        return "This is the test page";
    }
}

以下标记将窗体提交到 /Home/Test 终结点。The following markup submits the form to the /Home/Test endpoint.

<form method="post">
    <button asp-route="Custom">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-route="Custom">
</form>

之前的标记将生成以下 HTML:The previous markup generates following HTML:

<form method="post">
    <button formaction="/Home/Test">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/Home/Test">
</form>

输入标记帮助程序The Input Tag Helper

输入标记帮助程序将 HTML <input> 元素绑定到 Razor 视图中的模型表达式。The Input Tag Helper binds an HTML <input> element to a model expression in your razor view.

语法:Syntax:

<input asp-for="<Expression Name>">

输入标记帮助程序:The Input Tag Helper:

  • asp-for 属性中指定的表达式名称生成 idname HTML 属性。Generates the id and name HTML attributes for the expression name specified in the asp-for attribute. asp-for="Property1.Property2"m => m.Property1.Property2 相等。asp-for="Property1.Property2" is equivalent to m => m.Property1.Property2. 表达式的名称用于 asp-for 属性值。The name of the expression is what is used for the asp-for attribute value. 有关其他信息,请参阅表达式名称部分。See the Expression names section for additional information.

  • 根据模型类型和应用于模型属性的数据注释特性设置 HTML type 特性值Sets the HTML type attribute value based on the model type and data annotation attributes applied to the model property

  • 如果已经指定,不会覆盖 HTML type 属性值Won't overwrite the HTML type attribute value when one is specified

  • 通过应用于模型属性的数据注释特性生成 HTML5 验证特性Generates HTML5 validation attributes from data annotation attributes applied to model properties

  • 具有与 Html.TextBoxForHtml.EditorFor 重叠的 HTML 帮助程序功能。Has an HTML Helper feature overlap with Html.TextBoxFor and Html.EditorFor. 有关详细信息,请参阅输入标记帮助程序的 HTML 帮助程序替代项部分。See the HTML Helper alternatives to Input Tag Helper section for details.

  • 提供强类型化。Provides strong typing. 如果属性的名称更改,但未更新标记帮助程序,则会收到类似如下内容的错误:If the name of the property changes and you don't update the Tag Helper you'll get an error similar to the following:

An error occurred during the compilation of a resource required to process
this request. Please review the following specific error details and modify
your source code appropriately.

Type expected
 'RegisterViewModel' does not contain a definition for 'Email' and no
 extension method 'Email' accepting a first argument of type 'RegisterViewModel'
 could be found (are you missing a using directive or an assembly reference?)

Input 标记帮助程序根据 .NET 类型设置 HTML type 属性。The Input Tag Helper sets the HTML type attribute based on the .NET type. 下表列出一些常见的 .NET 类型和生成的 HTML 类型(并未列出每个 .NET 类型)。The following table lists some common .NET types and generated HTML type (not every .NET type is listed).

.NET 类型.NET type 输入类型Input Type
BoolBool type="checkbox"type="checkbox"
StringString type="text"type="text"
DateTimeDateTime type="datetime-local"type="datetime-local"
ByteByte type="number"type="number"
IntInt type="number"type="number"
Single、DoubleSingle, Double type="number"type="number"

下表显示输入标记帮助程序会映射到特定输入类型的一些常见数据注释属性(并未列出每个验证属性):The following table shows some common data annotations attributes that the input tag helper will map to specific input types (not every validation attribute is listed):

特性Attribute 输入类型Input Type
[EmailAddress][EmailAddress] type="email"type="email"
[Url][Url] type="url"type="url"
[HiddenInput][HiddenInput] type="hidden"type="hidden"
[Phone][Phone] type="tel"type="tel"
[DataType(DataType.Password)][DataType(DataType.Password)] type="password"type="password"
[DataType(DataType.Date)][DataType(DataType.Date)] type="date"type="date"
[DataType(DataType.Time)][DataType(DataType.Time)] type="time"type="time"

示例:Sample:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterInput" method="post">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    <button type="submit">Register</button>
</form>

上述代码生成以下 HTML:The code above generates the following HTML:

  <form method="post" action="/Demo/RegisterInput">
      Email:
      <input type="email" data-val="true"
             data-val-email="The Email Address field is not a valid email address."
             data-val-required="The Email Address field is required."
             id="Email" name="Email" value=""><br>
      Password:
      <input type="password" data-val="true"
             data-val-required="The Password field is required."
             id="Password" name="Password"><br>
      <button type="submit">Register</button>
      <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
   </form>

应用于 EmailPassword 属性的数据注释在模型中生成元数据。The data annotations applied to the Email and Password properties generate metadata on the model. 输入标记帮助程序使用模型元数据并生成 HTML5 data-val-* 属性(请参阅模型验证)。The Input Tag Helper consumes the model metadata and produces HTML5 data-val-* attributes (see Model Validation). 这些属性描述要附加到输入字段的验证程序。These attributes describe the validators to attach to the input fields. 这样可以提供非介入式 HTML5 和 jQuery 验证。This provides unobtrusive HTML5 and jQuery validation. 非介入式属性具有格式 data-val-rule="Error Message",其中规则是验证规则的名称(例如 data-val-requireddata-val-emaildata-val-maxlength 等)。如果在属性中提供错误消息,则该错误消息会作为 data-val-rule 属性的值显示。The unobtrusive attributes have the format data-val-rule="Error Message", where rule is the name of the validation rule (such as data-val-required, data-val-email, data-val-maxlength, etc.) If an error message is provided in the attribute, it's displayed as the value for the data-val-rule attribute. 还有表单 data-val-ruleName-argumentName="argumentValue" 的属性,这些属性提供有关规则的其他详细信息,例如,data-val-maxlength-max="1024"There are also attributes of the form data-val-ruleName-argumentName="argumentValue" that provide additional details about the rule, for example, data-val-maxlength-max="1024" .

输入标记帮助程序的 HTML 帮助程序替代项HTML Helper alternatives to Input Tag Helper

Html.TextBoxHtml.TextBoxForHtml.EditorHtml.EditorFor 与输入标记帮助程序的功能存在重叠。Html.TextBox, Html.TextBoxFor, Html.Editor and Html.EditorFor have overlapping features with the Input Tag Helper. 输入标记帮助程序会自动设置 type 属性;而 Html.TextBoxHtml.TextBoxFor 不会。The Input Tag Helper will automatically set the type attribute; Html.TextBox and Html.TextBoxFor won't. Html.EditorHtml.EditorFor 处理集合、复杂对象和模板;而输入标记帮助程序不会。Html.Editor and Html.EditorFor handle collections, complex objects and templates; the Input Tag Helper doesn't. 输入标记帮助程序、Html.EditorForHtml.TextBoxFor 是强类型(使用 lambda 表达式);而 Html.TextBoxHtml.Editor 不是(使用表达式名称)。The Input Tag Helper, Html.EditorFor and Html.TextBoxFor are strongly typed (they use lambda expressions); Html.TextBox and Html.Editor are not (they use expression names).

HtmlAttributesHtmlAttributes

@Html.Editor()@Html.EditorFor() 在执行其默认模板时使用名为 htmlAttributes 的特殊 ViewDataDictionary 条目。@Html.Editor() and @Html.EditorFor() use a special ViewDataDictionary entry named htmlAttributes when executing their default templates. 此行为可选择使用 additionalViewData 参数增强。This behavior is optionally augmented using additionalViewData parameters. 键“htmlAttributes”区分大小写。The key "htmlAttributes" is case-insensitive. 键“htmlAttributes”的处理方式与传递到输入帮助程序的 htmlAttributes 对象(例如 @Html.TextBox())的处理方式类似。The key "htmlAttributes" is handled similarly to the htmlAttributes object passed to input helpers like @Html.TextBox().

@Html.EditorFor(model => model.YourProperty, 
  new { htmlAttributes = new { @class="myCssClass", style="Width:100px" } })

表达式名称Expression names

asp-for 属性值是 ModelExpression,并且是 lambda 表达式的右侧。The asp-for attribute value is a ModelExpression and the right hand side of a lambda expression. 因此,asp-for="Property1" 在生成的代码中变成 m => m.Property1,这也是无需使用 Model 前缀的原因。Therefore, asp-for="Property1" becomes m => m.Property1 in the generated code which is why you don't need to prefix with Model. “@”字符可用作内联表达式的开头,并移到 m. 前面:You can use the "@" character to start an inline expression and move before the m.:

@{
       var joe = "Joe";
   }
   <input asp-for="@joe">

生成以下 HTML:Generates the following:

<input type="text" id="joe" name="joe" value="Joe">

使用集合属性时,asp-for="CollectionProperty[23].Member"i 具有值 23 时生成与 asp-for="CollectionProperty[i].Member" 相同的名称。With collection properties, asp-for="CollectionProperty[23].Member" generates the same name as asp-for="CollectionProperty[i].Member" when i has the value 23.

在 ASP.NET Core MVC 计算 ModelExpression 的值时,它会检查多个源,包括 ModelStateWhen ASP.NET Core MVC calculates the value of ModelExpression, it inspects several sources, including ModelState. <input type="text" asp-for="@Name"> 为例。Consider <input type="text" asp-for="@Name">. 计算出的 value 属性是第一个非 null 值,属于:The calculated value attribute is the first non-null value from:

  • 带有“Name”键的 ModelState 条目。ModelState entry with key "Name".
  • Model.Name 表达式的结果。Result of the expression Model.Name.

还可使用视图模型的属性路径导航到子属性。You can also navigate to child properties using the property path of the view model. 设想一个包含子 Address 属性的更复杂的模型类。Consider a more complex model class that contains a child Address property.

public class AddressViewModel
{
    public string AddressLine1 { get; set; }
}
public class RegisterAddressViewModel
{
    public string Email { get; set; }

    [DataType(DataType.Password)]
    public string Password { get; set; }

    public AddressViewModel Address { get; set; }
}

在视图中,绑定到 Address.AddressLine1In the view, we bind to Address.AddressLine1:

@model RegisterAddressViewModel

<form asp-controller="Demo" asp-action="RegisterAddress" method="post">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    Address: <input asp-for="Address.AddressLine1" /><br />
    <button type="submit">Register</button>
</form>

Address.AddressLine1 生成以下 HTML:The following HTML is generated for Address.AddressLine1:

<input type="text" id="Address_AddressLine1" name="Address.AddressLine1" value="">

表达式名称和集合Expression names and Collections

包含 Colors 数组的模型示例:Sample, a model containing an array of Colors:

public class Person
{
    public List<string> Colors { get; set; }

    public int Age { get; set; }
}

操作方法:The action method:

public IActionResult Edit(int id, int colorIndex)
   {
       ViewData["Index"] = colorIndex;
       return View(GetPerson(id));
   }

以下 Razor 显示如何访问特定 Color 元素:The following Razor shows how you access a specific Color element:

@model Person
@{
    var index = (int)ViewData["index"];
}

<form asp-controller="ToDo" asp-action="Edit" method="post">
    @Html.EditorFor(m => m.Colors[index])
    <label asp-for="Age"></label>
    <input asp-for="Age" /><br />
    <button type="submit">Post</button>
</form>

Views/Shared/EditorTemplates/String.cshtml 模板:The Views/Shared/EditorTemplates/String.cshtml template:

@model string

<label asp-for="@Model"></label>
<input asp-for="@Model" /> <br />

使用 List<T> 的示例:Sample using List<T>:

public class ToDoItem
{
    public string Name { get; set; }

    public bool IsDone { get; set; }
}

以下 Razor 演示如何循环访问集合:The following Razor shows how to iterate over a collection:

@model List<ToDoItem>

<form asp-controller="ToDo" asp-action="Edit" method="post">
    <table>
        <tr> <th>Name</th> <th>Is Done</th> </tr>

        @for (int i = 0; i < Model.Count; i++)
        {
            <tr>
                @Html.EditorFor(model => model[i])
            </tr>
        }

    </table>
    <button type="submit">Save</button>
</form>

Views/Shared/EditorTemplates/ToDoItem.cshtml 模板:The Views/Shared/EditorTemplates/ToDoItem.cshtml template:

@model ToDoItem

<td>
    <label asp-for="@Model.Name"></label>
    @Html.DisplayFor(model => model.Name)
</td>
<td>
    <input asp-for="@Model.IsDone" />
</td>

@*
    This template replaces the following Razor which evaluates the indexer three times.
    <td>
         <label asp-for="@Model[i].Name"></label>
         @Html.DisplayFor(model => model[i].Name)
     </td>
     <td>
         <input asp-for="@Model[i].IsDone" />
     </td>
*@

应尽量在 asp-forHtml.DisplayFor 等效上下文中使用值 foreachforeach should be used if possible when the value is going to be used in an asp-for or Html.DisplayFor equivalent context. 一般情况下,for 优于 foreach(如果情况允许使用的话),因为它不需要分配枚举器,但在 LINQ 表达式中评估索引器的成本高昂,应最大限度地减少使用它。In general, for is better than foreach (if the scenario allows it) because it doesn't need to allocate an enumerator; however, evaluating an indexer in a LINQ expression can be expensive and should be minimized.

 

备注

上述带有注释的示例代码演示如何将 lambda 表达式替换为 @ 运算符来访问列表中的每个 ToDoItemThe commented sample code above shows how you would replace the lambda expression with the @ operator to access each ToDoItem in the list.

文本区标记帮助程序The Textarea Tag Helper

Textarea Tag Helper 标记帮助程序类似于输入标记帮助程序。The Textarea Tag Helper tag helper is similar to the Input Tag Helper.

  • 通过模型为 <textarea> 元素生成 idname 属性以及数据验证属性。Generates the id and name attributes, and the data validation attributes from the model for a <textarea> element.

  • 提供强类型化。Provides strong typing.

  • HTML 帮助程序替代项:Html.TextAreaForHTML Helper alternative: Html.TextAreaFor

示例:Sample:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class DescriptionViewModel
    {
        [MinLength(5)]
        [MaxLength(1024)]
        public string Description { get; set; }
    }
}
@model DescriptionViewModel

<form asp-controller="Demo" asp-action="RegisterTextArea" method="post">
    <textarea asp-for="Description"></textarea>
    <button type="submit">Test</button>
</form>

生成以下 HTML:The following HTML is generated:

<form method="post" action="/Demo/RegisterTextArea">
  <textarea data-val="true"
   data-val-maxlength="The field Description must be a string or array type with a maximum length of &#x27;1024&#x27;."
   data-val-maxlength-max="1024"
   data-val-minlength="The field Description must be a string or array type with a minimum length of &#x27;5&#x27;."
   data-val-minlength-min="5"
   id="Description" name="Description">
  </textarea>
  <button type="submit">Test</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

标签标记帮助程序The Label Tag Helper

  • <label> 元素中为表达式名称生成标签描述和 for 属性Generates the label caption and for attribute on a <label> element for an expression name

  • HTML 帮助程序替代项:Html.LabelForHTML Helper alternative: Html.LabelFor.

Label Tag Helper 通过纯 HTML 标签元素提供如下优势:The Label Tag Helper provides the following benefits over a pure HTML label element:

  • 可自动从 Display 属性中获取描述性标签值。You automatically get the descriptive label value from the Display attribute. 预期的显示名称可能会随时间变化,Display 属性和标签标记帮助程序的组合会在其被使用的所有位置应用 DisplayThe intended display name might change over time, and the combination of Display attribute and Label Tag Helper will apply the Display everywhere it's used.

  • 源代码中的标记更少Less markup in source code

  • 模型属性的强类型化。Strong typing with the model property.

示例:Sample:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class SimpleViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }
    }
}

@model SimpleViewModel

<form asp-controller="Demo" asp-action="RegisterLabel" method="post">
    <label asp-for="Email"></label>
    <input asp-for="Email" /> <br />
</form>

<label> 元素生成以下 HTML:The following HTML is generated for the <label> element:

<label for="Email">Email Address</label>

标签标记帮助程序生成“Email”的 for 属性值,即与 <input> 元素关联的 ID。The Label Tag Helper generated the for attribute value of "Email", which is the ID associated with the <input> element. 标记帮助程序生成一致的 idfor 元素,方便将其正确关联。The Tag Helpers generate consistent id and for elements so they can be correctly associated. 本示例中的描述来自 Display 属性。The caption in this sample comes from the Display attribute. 如果模型不包含 Display 特性,描述将为表达式的属性名称。If the model didn't contain a Display attribute, the caption would be the property name of the expression.

验证标记帮助程序The Validation Tag Helpers

有两个验证标记帮助程序。There are two Validation Tag Helpers. Validation Message Tag Helper(为模型中的单个属性显示验证消息)和 Validation Summary Tag Helper(显示验证错误的摘要)。The Validation Message Tag Helper (which displays a validation message for a single property on your model), and the Validation Summary Tag Helper (which displays a summary of validation errors). Input Tag Helper 根据模型类的数据注释属性将 HTML5 客户端验证属性添加到输入元素中。The Input Tag Helper adds HTML5 client side validation attributes to input elements based on data annotation attributes on your model classes. 同时在服务器上执行验证。Validation is also performed on the server. 验证标记帮助程序会在发生验证错误时显示这些错误消息。The Validation Tag Helper displays these error messages when a validation error occurs.

验证消息标记帮助程序The Validation Message Tag Helper

  • HTML5 data-valmsg-for="property" 属性添加到 span 元素中,该元素会附加指定模型属性的输入字段中的验证错误消息。Adds the HTML5 data-valmsg-for="property" attribute to the span element, which attaches the validation error messages on the input field of the specified model property. jQuery 会在发生客户端验证错误时在 <span> 元素中显示错误消息。When a client side validation error occurs, jQuery displays the error message in the <span> element.

  • 还会在服务器上执行验证。Validation also takes place on the server. 客户端可能已禁用 JavaScript,一些验证仅可在服务器端执行。Clients may have JavaScript disabled and some validation can only be done on the server side.

  • HTML 帮助程序替代项:Html.ValidationMessageForHTML Helper alternative: Html.ValidationMessageFor

Validation Message Tag Helper 与 HTML span 元素中的 asp-validation-for 属性配合使用。The Validation Message Tag Helper is used with the asp-validation-for attribute on a HTML span element.

<span asp-validation-for="Email"></span>

验证消息标记帮助程序会生成以下 HTML:The Validation Message Tag Helper will generate the following HTML:

<span class="field-validation-valid"
  data-valmsg-for="Email"
  data-valmsg-replace="true"></span>

对于同一属性,通常在 Input 标记帮助程序后使用 Validation Message Tag HelperYou generally use the Validation Message Tag Helper after an Input Tag Helper for the same property. 这样做可在导致错误的输入附近显示所有验证错误消息。Doing so displays any validation error messages near the input that caused the error.

备注

必须拥有包含正确的 JavaScript 和 jQuery 脚本引用的视图才能执行客户端验证。You must have a view with the correct JavaScript and jQuery script references in place for client side validation. 有关详细信息,请参阅模型验证See Model Validation for more information.

发生服务器端验证错误时(例如,禁用自定义服务器端验证或客户端验证时),MVC 会将该错误消息作为 <span> 元素的主体。When a server side validation error occurs (for example when you have custom server side validation or client-side validation is disabled), MVC places that error message as the body of the <span> element.

<span class="field-validation-error" data-valmsg-for="Email"
            data-valmsg-replace="true">
   The Email Address field is required.
</span>

验证摘要标记帮助程序The Validation Summary Tag Helper

  • 针对具有 asp-validation-summary 属性的 <div> 元素Targets <div> elements with the asp-validation-summary attribute

  • HTML 帮助程序替代项:@Html.ValidationSummaryHTML Helper alternative: @Html.ValidationSummary

Validation Summary Tag Helper 用于显示验证消息的摘要。The Validation Summary Tag Helper is used to display a summary of validation messages. asp-validation-summary 属性值可以是以下任意值:The asp-validation-summary attribute value can be any of the following:

asp-validation-summaryasp-validation-summary 显示的验证消息Validation messages displayed
ValidationSummary.AllValidationSummary.All 属性和模型级别Property and model level
ValidationSummary.ModelOnlyValidationSummary.ModelOnly 模型Model
ValidationSummary.NoneValidationSummary.None None

示例Sample

在以下示例中,数据模型使用 DataAnnotation 属性修饰,在 <input> 元素中生成验证错误消息。In the following example, the data model is decorated with DataAnnotation attributes, which generates validation error messages on the <input> element. 验证标记帮助程序会在发生验证错误时显示错误消息:When a validation error occurs, the Validation Tag Helper displays the error message:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterValidation" method="post">
    <div asp-validation-summary="ModelOnly"></div>
    Email:  <input asp-for="Email" /> <br />
    <span asp-validation-for="Email"></span><br />
    Password: <input asp-for="Password" /><br />
    <span asp-validation-for="Password"></span><br />
    <button type="submit">Register</button>
</form>

生成的 HTML(如果模型有效):The generated HTML (when the model is valid):

<form action="/DemoReg/Register" method="post">
  <div class="validation-summary-valid" data-valmsg-summary="true">
  <ul><li style="display:none"></li></ul></div>
  Email:  <input name="Email" id="Email" type="email" value=""
   data-val-required="The Email field is required."
   data-val-email="The Email field is not a valid email address."
   data-val="true"><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Email"></span><br>
  Password: <input name="Password" id="Password" type="password"
   data-val-required="The Password field is required." data-val="true"><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Password"></span><br>
  <button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

选择标记帮助程序The Select Tag Helper

  • 为模型属性生成 select 元素和关联的 option 元素。Generates select and associated option elements for properties of your model.

  • 具有 HTML 帮助程序替代项 Html.DropDownListForHtml.ListBoxForHas an HTML Helper alternative Html.DropDownListFor and Html.ListBoxFor

Select Tag Helper asp-forselect 元素指定模型属性名称,asp-items 指定 option 元素。The Select Tag Helper asp-for specifies the model property name for the select element and asp-items specifies the option elements. 例如:For example:

<select asp-for="Country" asp-items="Model.Countries"></select> 

示例:Sample:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModel
    {
        public string Country { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            new SelectListItem { Value = "US", Text = "USA"  },
        };
    }
}

Index 方法初始化 CountryViewModel,设置选定的国家/地区并将其传递到 Index 视图。The Index method initializes the CountryViewModel, sets the selected country and passes it to the Index view.

public IActionResult Index()
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}

HTTP POST Index 方法显示选定内容:The HTTP POST Index method displays the selection:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(CountryViewModel model)
{
    if (ModelState.IsValid)
    {
        var msg = model.Country + " selected";
        return RedirectToAction("IndexSuccess", new { message = msg });
    }

    // If we got this far, something failed; redisplay form.
    return View(model);
}

Index 视图:The Index view:

@model CountryViewModel

<form asp-controller="Home" asp-action="Index" method="post">
    <select asp-for="Country" asp-items="Model.Countries"></select> 
    <br /><button type="submit">Register</button>
</form>

生成以下 HTML(选择“CA”时):Which generates the following HTML (with "CA" selected):

<form method="post" action="/">
     <select id="Country" name="Country">
       <option value="MX">Mexico</option>
       <option selected="selected" value="CA">Canada</option>
       <option value="US">USA</option>
     </select>
       <br /><button type="submit">Register</button>
     <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
   </form>

备注

不建议将 ViewBagViewData 与选择标记帮助程序配合使用。We don't recommend using ViewBag or ViewData with the Select Tag Helper. 视图模型在提供 MVC 元数据方面更可靠且通常更不容易出现问题。A view model is more robust at providing MVC metadata and generally less problematic.

asp-for 属性值是特殊情况,它不要求提供 Model 前缀,但其他标记帮助程序属性需要该前缀(例如 asp-itemsThe asp-for attribute value is a special case and doesn't require a Model prefix, the other Tag Helper attributes do (such as asp-items)

<select asp-for="Country" asp-items="Model.Countries"></select> 

枚举绑定Enum binding

通常可方便地将 <select>enum 属性配合使用并通过 enum 值生成 SelectListItem 元素。It's often convenient to use <select> with an enum property and generate the SelectListItem elements from the enum values.

示例:Sample:

    public class CountryEnumViewModel
    {
        public CountryEnum EnumCountry { get; set; }
    }
}
using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

GetEnumSelectList 方法为枚举生成 SelectList 对象。The GetEnumSelectList method generates a SelectList object for an enum.

@model CountryEnumViewModel

<form asp-controller="Home" asp-action="IndexEnum" method="post">
    <select asp-for="EnumCountry" 
            asp-items="Html.GetEnumSelectList<CountryEnum>()">
    </select> 
    <br /><button type="submit">Register</button>
</form>

可使用 Display 属性修饰枚举器列表,以获取更丰富的 UI:You can decorate your enumerator list with the Display attribute to get a richer UI:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

生成以下 HTML:The following HTML is generated:

  <form method="post" action="/Home/IndexEnum">
         <select data-val="true" data-val-required="The EnumCountry field is required."
                 id="EnumCountry" name="EnumCountry">
             <option value="0">United Mexican States</option>
             <option value="1">United States of America</option>
             <option value="2">Canada</option>
             <option value="3">France</option>
             <option value="4">Germany</option>
             <option selected="selected" value="5">Spain</option>
         </select>
         <br /><button type="submit">Register</button>
         <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
    </form>

选项组Option Group

如果视图模型包含一个或多个 SelectListGroup 对象,则会生成 HTML <optgroup> 元素。The HTML <optgroup> element is generated when the view model contains one or more SelectListGroup objects.

CountryViewModelGroupSelectListItem 元素分组为“North America”组和“Europe”组:The CountryViewModelGroup groups the SelectListItem elements into the "North America" and "Europe" groups:

public class CountryViewModelGroup
{
    public CountryViewModelGroup()
    {
        var NorthAmericaGroup = new SelectListGroup { Name = "North America" };
        var EuropeGroup = new SelectListGroup { Name = "Europe" };

        Countries = new List<SelectListItem>
        {
            new SelectListItem
            {
                Value = "MEX",
                Text = "Mexico",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "CAN",
                Text = "Canada",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "US",
                Text = "USA",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "FR",
                Text = "France",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "ES",
                Text = "Spain",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "DE",
                Text = "Germany",
                Group = EuropeGroup
            }
      };
    }

    public string Country { get; set; }

    public List<SelectListItem> Countries { get; }

两个组如下所示:The two groups are shown below:

选项组示例

生成的 HTML:The generated HTML:

 <form method="post" action="/Home/IndexGroup">
      <select id="Country" name="Country">
          <optgroup label="North America">
              <option value="MEX">Mexico</option>
              <option value="CAN">Canada</option>
              <option value="US">USA</option>
          </optgroup>
          <optgroup label="Europe">
              <option value="FR">France</option>
              <option value="ES">Spain</option>
              <option value="DE">Germany</option>
          </optgroup>
      </select>
      <br /><button type="submit">Register</button>
      <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

多重选择Multiple select

如果 asp-for 属性中指定的属性为 IEnumerable,选择标记帮助程序会自动生成 multiple = "multiple" 属性。The Select Tag Helper will automatically generate the multiple = "multiple" attribute if the property specified in the asp-for attribute is an IEnumerable. 例如,如果给定以下模型:For example, given the following model:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModelIEnumerable
    {
        public IEnumerable<string> CountryCodes { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            new SelectListItem { Value = "US", Text = "USA"    },
            new SelectListItem { Value = "FR", Text = "France" },
            new SelectListItem { Value = "ES", Text = "Spain"  },
            new SelectListItem { Value = "DE", Text = "Germany"}
         };
    }
}

及以下视图:With the following view:

@model CountryViewModelIEnumerable

<form asp-controller="Home" asp-action="IndexMultiSelect" method="post">
    <select asp-for="CountryCodes" asp-items="Model.Countries"></select> 
    <br /><button type="submit">Register</button>
</form>

则会生成以下 HTML:Generates the following HTML:

<form method="post" action="/Home/IndexMultiSelect">
    <select id="CountryCodes"
    multiple="multiple"
    name="CountryCodes"><option value="MX">Mexico</option>
<option value="CA">Canada</option>
<option value="US">USA</option>
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="DE">Germany</option>
</select>
    <br /><button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

无选定内容No selection

如果发现自己在多个页面中使用“未指定”选项,可创建模板用于消除重复的 HTML:If you find yourself using the "not specified" option in multiple pages, you can create a template to eliminate repeating the HTML:

@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    @Html.EditorForModel()
    <br /><button type="submit">Register</button>
</form>

Views/Shared/EditorTemplates/CountryViewModel.cshtml 模板:The Views/Shared/EditorTemplates/CountryViewModel.cshtml template:

@model CountryViewModel

<select asp-for="Country" asp-items="Model.Countries">
    <option value="">--none--</option>
</select>

添加 HTML <option> 元素并不局限于无选定内容用例。Adding HTML <option> elements isn't limited to the No selection case. 例如,以下视图和操作方法会生成与上述代码类似的 HTML:For example, the following view and action method will generate HTML similar to the code above:

public IActionResult IndexNone()
{
    var model = new CountryViewModel();
    model.Insert(0, new SelectListItem("<none>", ""));
    return View(model);
}
@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    <select asp-for="Country">
        <option value="">&lt;none&gt;</option>
        <option value="MX">Mexico</option>
        <option value="CA">Canada</option>
        <option value="US">USA</option>
    </select> 
    <br /><button type="submit">Register</button>
</form>

根据当前的 Country 值选择正确的 <option> 元素(包含 selected="selected" 属性)。The correct <option> element will be selected ( contain the selected="selected" attribute) depending on the current Country value.

public IActionResult IndexOption(int id)
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}
 <form method="post" action="/Home/IndexEmpty">
      <select id="Country" name="Country">
          <option value="">&lt;none&gt;</option>
          <option value="MX">Mexico</option>
          <option value="CA" selected="selected">Canada</option>
          <option value="US">USA</option>
      </select>
      <br /><button type="submit">Register</button>
   <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

其他资源Additional resources