第8章 使用标记帮助工具构建表单(ASP.NET Core in Action, 2nd Edition)

发布时间 2023-04-10 14:33:58作者: 码农小白修炼记

本章包括

  • 使用Tag Helpers轻松构建表单
  • 使用锚标记帮助程序生成URL
  • 使用Tag Helpers为Razor添加功能

在第7章中,您了解了Razor模板以及如何使用它们为应用程序生成视图。通过混合HTML和C#,您可以创建动态应用程序,根据请求、登录用户或您可以访问的任何其他数据显示不同的数据。

显示动态数据是许多Web应用程序的一个重要方面,但它通常只占一半。除了向用户显示数据之外,您通常还需要用户能够将数据提交回应用程序。例如,您可以使用数据自定义视图,或通过将其保存到数据库来更新应用程序模型。对于传统的Web应用程序,此数据通常使用HTML表单提交。

在第6章中,您学习了模型绑定,即如何接受用户在请求中发送的数据,并将其转换为可在RazorPages中使用的C#对象。您还了解了验证,以及验证请求中发送的数据的重要性。您使用DataAnnotations属性来定义与模型关联的规则,以及其他关联的元数据,如属性的显示名称。

我们尚未研究的最后一个方面是如何构建用户用于在请求中发送数据的HTML表单。表单是用户在浏览器中与应用程序交互的关键方式之一,因此,为应用程序正确定义表单并对用户友好非常重要。ASP.NET Core提供了一种实现这一点的功能,称为标记帮助程序。

标记帮助程序是ASP.NET Core的新功能。它们是Razor语法的补充,可用于自定义模板中生成的HTML。标记助手可以添加到其他标准HTML元素中,例如<input>,以根据C#模型自定义其属性,从而避免编写样板代码。标记帮助器也可以是独立的元素,可以用于生成完全自定义的HTML。

注意:记住,Razor和标记帮助程序是用于服务器端HTML渲染的。您不能在Angular或React等前端框架中直接使用Tag Helpers。

如果您使用过以前版本的ASP.NET,那么标记帮助程序听起来可能会让人想起HTML帮助程序,它也可以用于基于C#类生成HTML。标记帮助程序是HTML帮助程序的逻辑继承者,因为它们提供了比以前以C#为中心的帮助程序更精简的语法。HTML帮助器在ASP.NET Core中仍然可用,因此如果您要将一些旧模板转换为ASP.NET Core,您仍然可以在模板中使用它们,但我不会在本书中介绍它们。

在本章中,您将主要学习如何在构建表单时使用标记辅助对象。它们简化了生成正确元素名称和ID的过程,以便在表单发送回应用程序时可以无缝地进行模型绑定。为了将它们放到上下文中,您将继续构建您在前几章中看到的货币转换器应用程序。您将添加向其提交货币兑换请求、验证数据以及使用Tag Helpers在表单上重新显示错误的功能,以便为您进行这些吃力不讨好的工作,如图8.1所示。

在开发应用程序时,您将遇到处理表单时遇到的最常见的标记帮助程序。您还将了解如何使用Tag Helpers简化其他常见任务,例如生成链接、在应用程序中有条件地显示数据,以及确保用户在刷新浏览器时看到最新版本的图像文件。

首先,我将讨论一下当Razor已经可以通过在文件中结合C#和HTML生成任何您喜欢的HTML时,为什么需要Tag Helpers。

图8.1 使用Tag Helpers构建的货币转换器应用程序表单。标签、下拉列表、输入元素和验证消息都是使用Tag Helpers生成的。

8.1 为编辑提供标签帮助

Razor模板中混合使用C#和HTML的常见问题之一是,您不能轻松地使用标准HTML编辑工具;C#代码中的所有@和{ }符号都会使编辑器感到困惑。阅读模板对人们来说同样困难;在C#和HTML之间切换范例有时会有点不和谐。

当Visual Studio是构建ASP.NET网站的唯一受支持的方法时,这可以说不是问题,因为它显然可以毫无问题地理解模板,并为编辑器着色。但随着ASP.NET Core的跨平台发展,能够与其他编辑器更好协作的愿望再次出现。

这是Tag Helpers的主要动机之一。它们通过添加外观属性(通常从asp-*开始)无缝集成到标准HTML语法中。它们最常用于生成HTML表单,如下表所示。此列表显示了货币转换器应用程序第一次迭代的视图,您可以在其中选择要转换的货币和数量。

清单8.1 使用Tag Helpers的用户注册表单

@page
@model ConvertModel    <!--这是Razor Page Convert.cshtml的视图。模型类型为ConvertModel。-->
<form method="post">
    <div class="form-group">
        <label asp-for="CurrencyFrom"></label>    <!--asp for on Labels基于视图模型为标签生成标题。-->
        <input class="form-control" asp-for="CurrencyFrom" />    <!--asp for on Inputs为模型生成正确的类型、值、名称和验证属性。-->
        <span asp-validation-for="CurrencyFrom"></span>    <!--使用标记帮助程序将验证消息写入span。-->
    </div>
    <div class="form-group">
        <label asp-for="Quantity"></label>
        <input class="form-control" asp-for="Quantity" />
        <span asp-validation-for="Quantity"></span>
    </div>
    <div class="form-group">
        <label asp-for="CurrencyTo"></label>
        <input class="form-control" asp-for="CurrencyTo" />
        <span asp-validation-for="CurrencyTo"></span>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

乍一看,你甚至可能看不到标记帮助程序,它们与HTML很好地融合在一起!这使得使用任何标准HTML文本编辑器都可以轻松编辑文件。但不要担心您牺牲了Visual Studio中的可读性,如图8.2所示,带有标记帮助器的元素与标准HTML<div>元素和<input>元素上的标准HTML类属性明显不同。与Razor文件中的其他C#代码一样,被引用的视图模型的C#属性(在本例中为CurrencyFrom)也仍然被着色。当然,正如你所料,你会得到IntelliSense。

注:其他编辑器如Visual Studio Code、JetBrains Rider和Visual Studio for Mac也包括语法高亮和智能感知支持。

图8.2 在Visual Studio中,标记帮助程序通过粗体和不同的颜色与普通元素区分开来,C#为阴影,IntelliSense可用。

标记帮助是标准HTML元素(或整个新元素)上的额外属性,通过修改附加的HTML元素来工作。它们可以让您轻松地将服务器端值(如PageModel上显示的值)与生成的HTML集成。

注意,清单8.1没有指定要在标签中显示的标题。相反,您声明性地使用asp-for="CurrencyFrom"来表示,"对于这个<label>,使用CurrencyFrom属性来确定要使用的标题。”类似地,对于<input>元素,使用Tag Helpers

  • 自动从PageModel属性填充值。
  • 选择正确的id和名称,这样当表单被POST回RazorPage时,属性将被正确绑定。
  • 选择要显示的正确输入类型(例如,“number”属性的数字输入)。
  • 显示任何验证错误,如图8.3所示。

注意:要了解更多关于Tag helper的内部信息,请阅读 http://mng.bz/Idb0 上的文档。

图8.3 标记帮助程序与DataAnnotations属性提供的元数据以及属性类型本身挂钩。Validation Tag Helper甚至可以根据ModelState填充错误消息,正如您在上一章验证中看到的那样。

标记帮助程序可以通过修改它们所应用的HTML元素来执行各种功能。本章介绍了许多常见的标记帮助程序以及如何使用它们,但并不是详尽的列表。我没有涵盖ASP.NET Core中开箱即用的所有助手(每个版本都有更多的助手!),您可以轻松创建自己的助手,如第19章所示。或者,您可以使用NuGet或GitHub上其他人发布的内容。与所有ASP.NET Core一样,微软正在GitHub上公开开发标记帮助程序,因此您可以随时查看源代码以了解它们是如何实现的。

提示:一个很好的例子是 Damian Edwards (ASP.NET Core团队)的 TagHelper pack: https://github.com/DamianEdwards/TagHelperPack

WebForms快速回忆
对于那些在WebForms时代使用ASP.NET的人来说,在MVC模式用于Web开发之前,Tag Helpers可能会引发糟糕的回忆。尽管asp前缀有点让人联想到ASP.NET Web服务器控件定义,但不要担心这两者是不同的。
Web服务器控件直接添加到页面的支持C#类中,并且具有广泛的范围,可以修改页面中看似无关的部分。再加上它们有一个复杂的生命周期,在不工作时很难理解和调试。尝试处理这种复杂程度的工作的风险很难被忘记,但Tag Helpers不一样。
标记帮助程序没有生命周期,它们参与了所附加元素的呈现,仅此而已。它们可以修改所附加的HTML元素,但不能修改页面上的任何其他内容,从而使它们在概念上更加简单。他们带来的另一个功能是让多个标记帮助器作用于单个元素,这是Web服务器控件无法轻松实现的。
总之,如果您正在编写Razor模板,如果您将Tag Helpers作为其语法的一个组成部分,您将获得更愉快的体验。它们带来了很多好处,但没有明显的缺点,您的跨平台编辑朋友将感谢您!

8.2 使用Tag Helpers创建表单

在本节中,您将学习如何使用一些最有用的标记帮助器:用于表单的标记帮助程序。您将学习如何使用它们基于PageModel的属性生成HTML标记,创建正确的id和名称属性,并将元素的值设置为模型属性的值(除其他外)。此功能显著减少了需要手动编写的标记量。

假设您正在为货币转换器应用程序构建结账页面,并且需要在结账页面上捕获用户的详细信息。在第6章中,您构建了UserBindingModel模型(如清单8.2所示),添加了DataAnnotations属性进行验证,并了解了如何在POST中将其绑定到Razor Page。在本章中,您将看到如何通过将UserBindingModel公开为PageModel上的属性来为其创建视图。

警告:使用RazorPages,您通常在视图中公开用于模型绑定的同一对象。执行此操作时,必须小心不要在绑定模型中包含敏感值(不应编辑),以避免对应用程序进行大规模分配攻击。你可以在我的博客 http://mng.bz/RXw0 上阅读更多关于过度发布攻击的内容。

set; } [Required] [StringLength(100, ErrorMessage = "Maximum length is {1}")] [Display(Name = "Last name")] public string LastName { get; set; } [Required] [EmailAddress] public string Email { get; set; } [Phone(ErrorMessage = "Not a valid phone number.")] [Display(Name = "Phone number")] public string PhoneNumber { get; set; } }

UserBindingModel由许多DataAnnotations属性修饰。在第6章中,您看到当模型绑定到请求时,在执行页面处理程序之前,在模型验证期间使用这些属性。Razor模板语言还使用这些属性来提供在使用标记帮助程序时生成正确HTML所需的元数据。

您可以使用我在第6章中描述的模式,将UserBindindModel公开为PageModel的Input属性,以便在模型绑定和Razor视图中使用该模型:

public class CheckoutModel: PageModel
{
    [BindProperty]
    public UserBindingModel Input { get; set; }
}

在UserBindingModel属性、Tag Helpers和一点HTML的帮助下,您可以创建一个Razor视图,允许用户输入其详细信息,如图8.4所示。

图8.4 应用程序的签出页面。HTML是基于UserBindingModel生成的,使用标记帮助程序呈现所需的元素值、输入类型和验证消息。

生成此页面的Razor模板如清单8.3所示。这段代码使用了多种标记助手,包括

  • <Form>元素上的Form Tag Helper
  • 在<Label>上标记Tag Helper
  • <Input>上的输入Tag Helper
  • UserBindingModel中每个属性的验证元素上的验证消息Tag Helper

清单8.3 签出页面上用于绑定到UserBindingModel的Razor模板

@page
@model CheckoutModel    <!--CheckoutModel是PageModel,它在Input属性上公开UserBindingModel。-->
@{
    ViewData["Title"] = "Checkout";
}
<h1>@ViewData["Title"]</h1>
<form asp-page="Checkout">    <!--表单标记帮助程序使用路由来确定表单将发布到的URL。-->
    <div class="form-group">
        <label asp-for="Input.FirstName"></label>    <!--标签标记帮助程序使用属性上的DataAnnotations来确定要显示的标题。-->
        <input class="form-control" asp-for="Input.FirstName" />    <!--Input Tag Helper使用DataAnnotations来确定要生成的输入类型。-->
        <span asp-validation-for="Input.FirstName"></span>    <!--Validation Tag Helper显示与给定属性相关的错误消息。-->
    </div>
    <div class="form-group">
        <label asp-for="Input.LastName"></label>
        <input class="form-control" asp-for="Input.LastName" />
        <span asp-validation-for="Input.LastName"></span>
    </div>
    <div class="form-group">
        <label asp-for="Input.Email"></label>
        <input class="form-control" asp-for="Input.Email" />
        <span asp-validation-for="Input.Email"></span>
    </div>
    <div class="form-group">
        <label asp-for="Input.PhoneNumber"></label>
        <input class="form-control" asp-for="Input.PhoneNumber" />
        <span asp-validation-for="Input.PhoneNumber"></span>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

您可以在清单8.4中看到该模板生成的HTML标记。这个Razor标记和生成的HTML产生了如图8.4所示的结果。您可以看到,每个带有Tag Helper的HTML元素都在输出中进行了定制:<form>元素有一个action属性,<input>元素有基于引用属性名称的id和名称,<input>和<span>都有用于验证的data-*属性。

form action="/Checkout" method="post"> <div class="form-group"> <label for="Input_FirstName">Your name</label> <input class="form-control" type="text" data-val="true" data-val-length="Maximum length is 100" id="Input_FirstName" data-val-length-max="100" data-val-required="The Your name field is required." Maxlength="100" name="Input.FirstName" value="" /> <span data-valmsg-for="Input.FirstName" class="field-validation-valid" data-valmsg-replace="true"></span> </div> <div class="form-group"> <label for="Input_LastName">Your name</label> <input class="form-control" type="text" data-val="true" data-val-length="Maximum length is 100" id="Input_LastName" data-val-length-max="100" data-val-required="The Your name field is required." Maxlength="100" name="Input.LastName" value="" /> <span data-valmsg-for="Input.LastName" class="field-validation-valid" data-valmsg-replace="true"></span> </div> <div class="form-group"> <label for="Input_Email">Email</label> <input class="form-control" type="email" data-val="true" data-val-email="The Email field is not a valid e-mail address." Data-val-required="The Email field is required." Id="Input_Email" name="Input.Email" value="" /> <span class="text-danger field-validation-valid" data-valmsg-for="Input.Email" data-valmsg-replace="true"></span> </div> <div class="form-group"> <label for="Input_PhoneNumber">Phone number</label> <input class="form-control" type="tel" data-val="true" data-val-phone="Not a valid phone number." Id="Input_PhoneNumber" name="Input.PhoneNumber" value="" /> <span data-valmsg-for="Input.PhoneNumber" class="text-danger field-validation-valid" data-valmsg-replace="true"></span> </div> <button type="submit" class="btn btn-primary">Submit</button> <input name=" RequestVerificationToken" type="hidden" value="CfDJ8PkYhAINFx1JmYUVIDWbpPyy_TRUNCATED" /> </form>

哇,这是很多标记!如果您是新使用HTML的人,这可能看起来有点让人不知所措,但需要注意的是,您不必编写大部分内容!Tag Helpers为您处理了大部分内容。简言之,这基本上就是Tag Helpers;它们简化了构建HTML表单的复杂机制,让您专注于应用程序的整体设计,而不是编写样板标记。

注:如果您使用Razor来构建视图,标记助手将使您的生活更轻松,但它们完全是可选的。您可以自由编写原始HTML而不使用它们,也可以使用传统的HTML助手。

标记助手简化和抽象HTML生成过程,但他们通常会在不妨碍您的情况下这样做。如果需要最终生成的HTML具有特定属性,可以将其添加到标记中。您可以在前面的列表中看到,在<input>元素上定义了类属性,例如<input class="form-control" asp-for="Input.FirstName" />。它们从Razor直接传递到HTML输出。

提示:这与以前版本的ASP.NET中HTML Helpers的工作方式不同;HTML助手通常需要在生成的标记中设置属性。

比这更好的是,您还可以设置通常由Tag Helper生成的属性,例如<input>元素上的type属性。例如,如果PageModel上的FavoriteColor属性是字符串,那么默认情况下Tag Helpers将生成一个type=“text”的<input>元素。更新标记以使用HTML5颜色选择器类型很简单;在Razor视图中显式设置类型:

<input type="color" asp-for="FavoriteColor" />

提示:HTML5增加了大量的功能,包括许多以前可能没有遇到过的表单元素,例如范围输入和颜色选择器。我们不会在本书中介绍它们,但您可以在Mozilla开发者网络网站上阅读http://mng.bz/qOc1.

在本节中,您将从头开始构建货币计算器Razor模板,并在发现需要时添加标记助手。您可能会发现,您在构建的每个应用程序中都使用了大多数常见的标记帮助程序,即使是在一个简单的登录页面上。

8.2.1 表单标记帮助程序

毫无疑问,开始构建HTML表单的第一件事是<form>元素。在上一个示例中,<form>元素被一个asp-page Tag Helper属性扩充:

<form asp-page="Checkout">

这将导致操作和方法属性被添加到最终的HTML中,指示表单提交时应发送到哪个URL以及要使用的HTTP动词:

<form action="/Checkout" method="post">

通过设置asp页面属性,您可以在应用程序中指定一个不同的Razor页面,表单提交时将发布到该页面。如果省略了asp页面属性,表单将返回到其发送的URL。这在Razor Pages中很常见。通常在用于显示表单的同一RazorPage中处理表单发布的结果。

警告:如果忽略了asp-page属性,则必须手动添加method="post"属性。添加此属性很重要,这样表单就可以使用POST动词而不是默认的GET动词发送。对表单使用GET可能存在安全风险。

asp-page属性由FormTagHelper添加。这个Tag Helper使用提供的值为action属性生成URL,使用我在第5章末尾描述的路由的URL生成特性。

注:标记帮助程序可以使元素上的多个属性可用。将它们视为Tag Helper配置对象上的属性。添加一个asp属性将激活元素上的Tag Helper。添加其他属性可以覆盖其实现的其他默认值。

FormTagHelper在<Form>元素上提供了其他几个属性,您可以使用这些属性自定义生成的URL。希望您能从第5章中记住,您可以在生成URL时设置路由值。例如,如果您有一个名为Product.cshtml的Razor Page,它使用指令

@page "{id}"

那么页面的完整路由模板将是“Product/{id}”。要正确生成此页面的URL,必须提供{id}路由值。如何使用Form Tag Helper设置该值?

FormTagHelper定义了一个asp-route-*通配符属性,您可以使用它来设置任意的路由参数。将属性中的*设置为路由参数名称。例如,要设置id路由参数,您需要设置asp-route-id值(在下面的示例中显示为固定值5,但通常是动态的):

<form asp-page="Product" asp-route-id="5">

基于Product.cshtml Razor Page的路由模板,这将生成以下标记:

<form action="/Product/5" method="post">

您可以根据需要向<form>中添加任意数量的asp-route-*属性,以生成正确的操作URL。您还可以将RazorPage处理程序设置为使用asp-Page处理程序属性。这确保表单POST将由您指定的处理程序处理。

注意:Form Tag Helper有许多其他属性,例如asp-action和asp-controller,通常不需要与Razor Pages一起使用。只有在使用视图的MVC控制器时,这些才有用。尤其要注意asp-route属性,这与asp-route-*属性不同。前者用于指定命名路由(不与Razor Pages一起使用),后者用于指定URL生成期间要使用的路由值。

与所有其他Razor构造一样,您可以在Tag Helpers中使用PageModel中的C#值(或一般的C#)。例如,如果Page-Model的ProductId属性包含{id}路由值所需的值,则可以使用

<form asp-page="Product" asp-route-id="@Model.ProductId">

Form Tag Helper的主要工作是生成action属性,但它还执行一个额外的重要功能:生成一个隐藏的<input>字段,以防止跨站点请求伪造(CSRF)攻击。

定义:跨站点请求伪造(CSRF)攻击是一种网站攻击,可允许无关恶意网站在您的网站上执行操作。您将在第18章中详细了解它们。

您可以在清单8.4中的<Form>底部看到生成的隐藏<input>;它名为RequestVerificationToken,包含一个看似随机的字符串。该字段本身不会保护您,但我将在第18章中描述如何使用它来保护您的网站。Form Tag Helper在默认情况下生成它,因此您通常不需要担心它,但如果您需要禁用它,可以通过向<Form>元素添加asp-antifogery=“false”来实现。

FormTagHelper对于生成动作URL显然很有用,但现在是时候转向更有趣的元素了——您可以在浏览器中看到的元素!

8.2.2 标签帮助程序

货币转换器应用程序中的每个<input>字段都需要有一个相关的标签,以便用户知道<input>的用途。您可以通过手动键入字段名称并将for属性设置为适当的方式轻松创建这些字段,但幸运的是,有一个Tag Helper可以为您完成这一操作。

Label Tag Helper用于根据PageModel中的属性为<Label>元素生成标题(可见文本)和for属性。它是通过在asp-for属性中提供属性的名称来实现的:

<label asp-for="FirstName"></label>

Label Tag Helper使用您在第6章中看到的[Display]DataAnnotations属性来确定要显示的适当值。如果要为其生成标签的属性没有[Display]属性,则label Tag Helper将使用该属性的名称。考虑这样一个模型,其中FirstName属性具有[Display]属性,但Email属性没有:

public class UserModel
{
  [Display(Name = "Your name")]
  public string FirstName { get; set; } 
  public string Email { get; set; }
}

以下Razor

<label asp-for="FirstName"></label>
<label asp-for="Email"></label>

将生成此HTML:

<label for="FirstName">Your name</label>
<label for="Email">Email</label>

<label>元素内的标题文本使用[Display]属性中设置的值,如果是Email属性,则使用属性名称。还要注意,for属性是用属性的名称生成的。这是使用标记帮助器的一个关键好处——它与其他标记帮助器生成的元素ID挂钩,稍后您将看到。

注:for属性对于可访问性很重要。它指定标签引用的元素的ID。例如,这对于使用屏幕阅读器的用户来说很重要,因为他们可以知道表单字段与什么属性相关。

除了PageModel上的属性之外,还可以引用子对象上的子属性。例如,如我在第6章中所述,在RazorPage中创建一个嵌套类,将其作为属性公开,并使用[BindProperty]属性对其进行修饰是很常见的:

public class CheckoutModel: PageModel
{
  [BindProperty]
  public UserBindingModel Input { get; set; }
}

您可以像在任何其他C#代码中一样,通过在属性中“.”来引用UserBindingModel的FirstName属性。清单8.3显示了这方面的更多示例。

<label asp-for="Input.FirstName"></label>
<label asp-for="Input.Email"></label>

与标记帮助程序一样,标签标记帮助程序不会覆盖您自己设置的值。例如,如果不想使用助手生成的标题,可以手动插入自己的标题。以下代码,

<label asp-for="Email">Please enter your Email</label>

将生成此HTML:

<label for="Email">Please enter your Email</label>

与以往一样,如果您坚持标准约定,并且不重写这样的值,那么通常维护起来会更轻松,但选项是存在的。接下来是一个大的课题:输入和文本区域标记帮助程序。

8.2.3 输入和文本区域标记帮助程序

现在,您将进入表单的核心部分——处理用户输入的<input>元素。考虑到有这么多可能的输入类型,有多种不同的方式可以在浏览器中显示它们。例如,布尔值通常由复选框类型<input>元素表示,而整数值将使用数字类型<input>元素,日期将使用日期类型,如图8.5所示

图8.5 各种输入元素类型。每种类型的显示方式因浏览器而异。

为了处理这种多样性,输入标记帮助器是最强大的标记帮助器之一。它使用基于属性类型(bool、string、int等)和应用于它的任何DataAnnotations属性([EmailAddress]和[Phone]等)的信息来确定要生成的输入元素的类型。DataAnnotations还用于向生成的HTML添加数据val-*客户端验证属性。

考虑清单8.2中的Email属性,该属性用[EmailAddress]属性修饰。添加<input>与使用asp-for属性一样简单:

<input asp-for="Input.Email" />

该属性是一个字符串,因此通常Input Tag Helper会生成一个type=“text”的<Input>。但[EmailAddress]属性的添加提供了有关该属性的附加元数据。因此,Tag Helper生成一个HTML5<input>,类型为“email”:

<input type="email" id="Input_Email" name="Input.Email" value="test@example.com" data-val="true"
  data-val-email="The Email Address field is not a valid e-mail address." Data-val-required="The Email Address field is required."
  />

你可以从这个例子中去掉很多东西。首先,HTML元素的id和name属性是从属性的名称生成的。id属性的值与Label Tag Helper在其for属性Input_Email中生成的值相匹配。name属性的值保留了“.”表示法Input.Email,以便在将字段POST到RazorPage时,模型绑定可以正常工作。

此外,字段的初始值已设置为当前存储在属性中的值(如:test@example.com),元素的类型也被设置为HTML5电子邮件类型,而不是使用默认的文本类型。。

也许最引人注目的添加是一系列数据val-*属性。客户端JavaScript库(如jQuery)可以使用这些函数来提供DataAnnotations约束的客户端验证。客户端验证在用户输入的值无效时向用户提供即时反馈,提供了比单独使用服务器端验证更流畅的用户体验,如我在第6章中所述。

客户端验证

为了在应用程序中启用客户端验证,需要在HTML页面中添加一些jQuery库。特别是,您需要包含jQuery、jQuery-validation和jQuery-validation-unobtrusive这些不显眼的JavaScript库。您可以通过多种方式执行此操作,但最简单的方法是使用

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

默认模板包括这些脚本,这些脚本位于一个方便的部分模板中,您可以在脚本部分中添加到页面中。如果您使用的是默认布局,并且需要将客户端验证添加到视图中,请在视图中的某个位置添加以下部分:

@section Scripts{
  @Html.Partial("_ValidationScriptsPartial")
}

此部分视图引用wwwroot文件夹中的文件。默认的_layout模板包括jQuery本身,这是前端组件库Bootstrap所需要的。

Input Tag Helper尝试根据DataAnnotations属性或属性类型为给定属性选择最合适的模板。这是否会生成您所需的确切<input>类型,在一定程度上取决于您的应用程序。一如既往,您可以通过向Razor模板中的元素添加自己的类型属性来覆盖生成的类型。表8.1显示了一些常见数据类型如何映射到<input>类型,以及如何指定它们自己的数据类型。

 

如果Dec属性的值为1.2,则将生成类似于:

<input type=“text”id=“Dec”name=“Dec”value=“1.200”>

注意:十进制和双精度类型被呈现为文本字段而不是数字字段,您可能会感到惊讶。这是由于几个技术原因,主要与某些文化使用逗号和空格来呈现数字的方式有关。以文本形式呈现可以避免仅在某些浏览器区域性组合中出现的错误。

除了输入标记帮助程序之外,ASP.NET Core还提供了文本区域标记帮助程序。这以类似的方式工作,使用asp-for属性,但它附加到<textarea>元素:

<textarea asp-for="BigtextValue"></textarea>

这将生成类似于以下内容的HTML。请注意,属性值在标记内呈现,data-val-*验证元素照常附加:

<textarea data-val="true" id="BigtextValue" name="BigtextValue" data-val-length="Maximum length 200." data-val-length-max="200"
  data-val-required="The Multiline field is required." >
This is some text, I'm going to display it in a text area
</textarea>

希望,本节已经明确了标记帮助器可以减少多少类型,尤其是在与DataAnnotations一起使用它们来生成验证属性时。但这不仅仅是减少所需的击键次数;标记帮助程序确保生成的标记正确,并且具有正确的名称、id和格式,以便在将绑定模型发送到服务器时自动绑定它们。

有了<form>、<label>和<input>,您就可以构建大部分货币转换器表单。在我们查看显示验证消息之前,还有一个元素需要查看:<select>或下拉输入。

8.2.4 select 标记帮助程序

除了<input>字段之外,您将在Web表单上看到的一个常见元素是<select>元素或下拉列表框。例如,您的货币转换器应用程序可以使用<select>元素从列表中选择要转换的货币。

默认情况下,该元素显示一个项目列表,并允许您选择一个,但有几个变体,如图8.6所示。除了常规的下拉框外,您还可以显示列表框、添加多个选项或分组显示列表项。

图8.6 使用select Tag Helper显示<select>元素的许多方法。

要在Razor代码中使用<select>元素,需要在PageModel中包含两个属性:一个属性用于显示选项列表,另一个属性保存所选值。例如,清单8.5显示了Page-Model上的属性,用于创建图8.6所示的三个最左边的选择列表。显示组需要稍微不同的设置,稍后您将看到。

set; } //用于将用户的选择绑定到选择框的InputModel //要在选择框中显示的项目列表 public IEnumerable<SelectListItem> Items { get; set; } = new List<SelectListItem> { new SelectListItem{Value= "csharp", Text="C#"}, //这些属性将保存单选选择框所选的值。 new SelectListItem{Value= "python", Text= "Python"}, new SelectListItem{Value= "cpp", Text="C++"}, new SelectListItem{Value= "java", Text="Java"}, new SelectListItem{Value= "js", Text="JavaScript"}, new SelectListItem{Value= "ruby", Text="Ruby"}, }; public class InputModel { public string SelectedValue1 { get; set; } public string SelectedValue2 { get; set; } public IEnumerable<string> MultiValues { get; set; } //要创建多选列表框,请使用IEnumerable<> } }

此列表演示了使用<select>列表的许多方面:

  • SelectedValue1/SelectedValue2——用于保存用户选择的值。它们被模型绑定到从下拉列表框中选择的值,并用于在呈现表单时预先选择正确的项目。
  • MultiValues——用于保存多选列表的选定值。它是一个IEnumerable,因此它可以为每个<select>元素保存多个选择。
  • Items——提供要在<select>元素中显示的选项列表。请注意,元素类型必须是SelectListItem,它公开Value和Text属性,才能使用SelectTagHelper。这不是InputModel的一部分,因为我们不想将这些项建模绑定到请求,它们通常直接从应用程序模型加载或硬编码。

注意:Select Tag Helper仅适用于SelectListItem元素。这意味着您通常必须从特定于应用程序的项目列表集(例如,list<string>或list<MyClass>)转换为以UI为中心的list<SelectListItem>。

SelectTagHelper公开了可以添加到<Select>元素的aspfor和aspitems属性。对于Input Tag Helper,asp for属性指定PageModel中要绑定的属性。asp items属性为IEnumerable<SelectListItem>提供,以显示可用的<option>元素。

提示:通常希望在<select>列表中显示枚举选项列表。这非常常见,ASP.NET Core附带了一个帮助器,用于为任何枚举生成SelectListItem。如果您有TEnum类型的枚举,则可以使用asp items=“Html.GetEnum-SelectList<TEnum>()”在视图中生成可用选项。

以下列表显示了如何显示下拉列表、单选列表框和多选列表框。它使用上一个列表中的PageModel,将每个<select>列表绑定到不同的属性,但对所有列表重用相同的Items列表。

清单8.6 以三种不同方式显示select元素的Razor模板

@page
@model SelectListsModel
<!--通过绑定到aspfor中的标准属性来创建标准下拉选择列表-->
<select asp-for="Input.SelectedValue1" asp-items="Model.Items"></select>
<!--通过提供标准HTML大小属性创建高度为4的单选列表框-->
<select asp-for="Input.SelectedValue2" asp-items="Model.Items" size="4"></select>
<!--通过绑定到aspfor中的IEnumerable属性来创建多选列表框--> 
<select asp-for="Input.MultiValues" asp-items="Model.Items"></select>

希望您可以看到,用于生成下拉<select>列表的Razor与用于生成多选<select>的Razo几乎相同。如果绑定到的属性是IEnumerable,则SelectTagHelper负责将多个HTML属性添加到生成的输出中。

警告:asp-for属性不能包含Model。前缀另一方面,如果引用PageModel上的属性,asp items属性必须包含它。asp项属性也可以引用其他C#项,例如存储在ViewData中的对象,但使用PageModel属性是最好的方法。

到目前为止,您已经看到了如何绑定三种不同类型的选择列表,但我尚未从图8.6中介绍的一个是如何使用<optgroup>元素在列表框中显示组。幸运的是,您的Razor代码无需更改;您只需更新如何定义SelectListItems。

SelectListItem对象定义了一个Group属性,该属性指定了该项所属的Select-ListGroup。下面的列表显示了如何创建两个组,并使用类似于清单8.5所示的Page-Model将每个列表项分配给“动态”或“静态”组。最后一个列表项C#没有分配给组,因此它将显示为正常,没有<optgroup>。

string> SelectedValues { get; set; } //用于保存允许多次选择的选定值 public IEnumerable<SelectListItem> Items { get; set; } public SelectListsModel() //初始化构造函数中的列表项 { var dynamic = new SelectListGroup { Name = "Dynamic" }; var stat = new SelectListGroup { Name = "Static" }; Items = new List<SelectListItem> { //创建每个组的单个实例以传递给SelectListItems new SelectListItem { Value= "js", Text="Javascript", Group = dynamic }, new SelectListItem { Value= "cpp", Text="C++", Group = stat }, new SelectListItem { Value= "python", Text="Python", Group = dynamic //为每个SelectListItem设置适当的组 }, //如果SelectListItem没有Group,则不会将其添加到<optgroup>。 new SelectListItem { Value= "csharp", Text="C#", } }; } }

有了这一点,当将Razor渲染为HTML时,SelectTagHelper将根据需要生成<optgroup>元素。该Razor模板,

@page
@model SelectListsModel
<select asp-for="SelectedValues" asp-items="Model.Items"></select>

将呈现为HTML,如下所示:

<select id="SelectedValues" name="SelectedValues" multiple="multiple">
  <optgroup label="Dynamic">
    <option value="js">JavaScript</option>
    <option value="python">Python</option>
  </optgroup>
  <optgroup label="Static Languages">
    <option value="cpp">C++</option>
  </optgroup>
  <option value="csharp">C#</option>
</select>

使用<select>元素时的另一个常见要求是在列表中包含一个选项,该选项指示未选择任何值,如图8.7所示。如果没有这个额外选项,默认的<select>下拉列表将始终有一个值,并且它将默认为列表中的第一项。

您可以通过以下两种方式之一实现这一点:您可以将“not selected”选项添加到可用的SelectListItems中,也可以手动将该选项添加到Razor中,例如使用

<select asp-for="SelectedValue" asp-items="Model.Items">
  <option Value = "">**Not selected**</option>
</select>

这将在<select>元素的顶部添加一个额外的<option>,并带有一个空白的Value属性,允许您为用户提供一个“无选择”选项。

提示:向<select>元素添加“no selection”选项非常常见,您可能需要创建一个局部视图来封装此逻辑。

图8.7 如果没有“not selected”选项,<select>元素将始终具有值。如果您不希望默认选择<option>,这可能不是您想要的行为。

使用腰带下的Input Tag Helper和Select Tag Helper,您应该能够创建所需的大多数表单。除了一个例外,您现在已经拥有创建货币转换器应用程序所需的所有部件。

记住,无论何时接受用户的输入,都应始终验证数据。验证标记帮助程序提供了一种在表单上向用户显示模型验证错误的方法,而无需编写大量样板标记。

8.2.5 验证消息和验证摘要标签帮助程序

在8.2.3节中,您看到Input Tag Helper在表单输入元素本身上生成了必要的数据val-*验证属性。但您还需要一些-在哪里显示验证消息。通过使用asp验证属性,可以使用应用于<span>的验证消息标记帮助程序为视图模型中的每个属性实现这一点:

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

当客户端验证期间发生错误时,所引用属性的相应错误消息将显示在<span>中,如图8.8所示。如果服务器端验证失败并且表单正在重新显示,则还将使用此<span>元素显示适当的验证消息。

图8.8 通过使用Validation Message Tag Helper,可以在关联的<span>中显示验证消息。

与存储在ModelState中的Email属性相关的任何错误都将在元素体中呈现,并且元素将具有适当的属性以连接到jQuery验证中:

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

当用户更新Email<input>字段并执行客户端验证时,元素中显示的验证错误将被替换。

注:有关ModelState和服务器端模型验证的更多详细信息,请参阅第6章。

除了显示各个属性的验证消息外,还可以使用ValidationSummary TagHelper在<div>中显示所有验证消息的摘要,如图8.9所示。这将呈现一个包含模型状态错误列表的<ul>。

图8.9 显示验证错误的表单。Validation Message Tag Helper应用于<span>,靠近关联的输入。Validation Summary Tag Helper应用于<div>,通常位于表单的顶部或底部。

ValidationSummary标记帮助程序使用asp Validation-Summary属性并提供ValidationSummary枚举值,例如

<div asp-validation-summary="All"></div>

ValidationSummary枚举控制显示的值,它有三个可能的值:

  • None——不显示摘要。(我不知道你为什么要用这个。)
  • ModelOnly——仅显示与属性无关的错误。
  • All——显示与属性或模型相关的错误。

如果与页面相关的错误不是特定于单个属性,那么ValidationSummary标记帮助程序特别有用。这些可以通过使用空白键添加到模型状态,如清单8.8所示。在本例中,属性验证通过了,但我们提供了额外的模型级验证,以检查我们是否没有试图将货币转换为货币本身。

set; } [HttpPost] public IActionResult OnPost() { if(Input.CurrencyFrom == Input.CurrencyTo) //无法将货币转换为自身 { //通过使用空键添加未绑定到特定属性的模型级错误 ModelState.AddModelError( string.Empty, "Cannot convert currency to itself"); } if (!ModelState.IsValid) //如果存在任何特性级或模型级错误,请显示它们。 { return Page(); } //store the valid values somewhere etc return RedirectToPage("Checkout"); } }

如果没有Validation Summary Tag Helper,如果用户使用相同的货币两次,则仍然会添加模型级别的错误,并且表单将重新显示。不幸的是,没有视觉提示告诉用户为什么表单没有提交,这显然是个问题!通过添加Validation Summary Tag Helper,可以向用户显示模型级别的错误,以便他们纠正问题,如图8.10所示。

注意:为了简单起见,我将验证检查添加到页面处理程序中。一种更好的方法可能是创建一个自定义验证属性来实现这一点。这样,你的处理者就会保持精干,并坚持单一责任原则。您将在第20章中了解如何实现这一点。

图8.10 模型级错误仅由Validation Summary Tag Helper显示。如果没有一个,用户将不会有任何迹象表明表单上存在错误,因此无法更正错误。

本节介绍了可用于处理表单的大多数常见标记帮助程序,包括构建货币转换器表单所需的所有部件。他们应该为您提供在自己的应用程序中开始构建表单所需的一切。但表单并不是标记助手有用的唯一领域;它们通常适用于任何需要将服务器端逻辑与HTML生成混合的时候。

一个这样的例子是使用基于路由的URL生成来生成指向应用程序中其他页面的链接。考虑到在重构应用程序时,路由设计是流动的,如果必须手动进行,那么跟踪链接应该指向的确切URL将是一个维护噩梦。正如你所料,有一个标记助手:锚标记助手。

8.3 使用Anchor Tag Helper生成链接

在第5章的末尾,我展示了如何使用ActionResults从页面处理程序内部生成指向应用程序中其他页面的链接的URL。视图是您需要链接到应用程序中其他页面的另一个常见位置,通常通过具有指向相应URL的href属性的<a>元素。

在本节中,我将展示如何使用AnchorTagHelper使用路由生成给定RazorPage的URL。从概念上讲,这与FormTagHelper生成动作URL的方式几乎相同,如8.2.1节所示。在大多数情况下,使用Anchor Tag Helper也是相同的;您提供了asp页面和asp页面处理程序属性,以及必要的asp-route-*属性。默认的RazorPage模板使用AnchorTagHelper使用以下列表中的代码生成导航栏中显示的链接。

ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a> </li> </ul>

如您所见,每个<a>元素都有一个asp页面属性。此Tag Helper使用路由系统为<a>生成适当的URL,从而生成以下标记:

<ul class="nav navbar-nav">
  <li class="nav-item">
    <a class="nav-link text-dark" href="/">Home</a>
  </li>
  <li class="nav-item">
    <a class="nav-link text-dark" href="/Privacy">Privacy</a>
  </li>t
</ul>

URL在可能的情况下使用默认值,因此Index Razor Page生成简单的“/”URL,而不是“/Index”。

如果您需要对生成的URL进行更多控制,Anchor Tag Helper将公开您可以设置的几个附加属性,这些属性将在URL生成期间使用。这些是Razor Pages最常用的:

  • asp-page——设置要执行的Razor Page。
  • asp-page-handler——设置要执行的Razor Page处理程序。
  • asp-area——设置要使用的区域路由参数。区域可用于为应用程序提供额外的组织层。我不会在本书中详细介绍这些领域。它们是 MVC 的一个可选方面,通常只用于大型项目。你可以在这里阅读它们: http://mng.bz/3X64
  • asp-host——如果设置,链接将指向所提供的主机,并将生成绝对URL而不是相对URL。
  • asp-protocol——设置是否生成http或https链接。如果设置,它将生成绝对URL而不是相对URL。
  • asp-route-*——设置生成期间要使用的路由参数。可以为不同的路线参数多次添加。

通过使用Anchor Tag Helper及其属性,您可以使用路由系统生成URL,如第5章所述。这通过删除硬编码的URL来减少代码中的重复,否则您需要将其嵌入到所有视图中。

如果你发现自己在标记中编写重复的代码,那么很可能有人编写了一个标记助手来帮助你。下面一节中的附加版本标记助手是使用标记助手来减少所需的复杂代码量的一个很好的例子。

8.4 使用Append Version Tag Helper破坏缓存

Web开发的一个常见问题,无论是在开发应用程序时还是在应用程序投入生产时,都是确保浏览器都使用最新的文件。出于性能原因,浏览器通常在本地缓存文件并在后续请求中重用它们,而不是在每次请求文件时调用应用程序。

通常情况下,这是很好的,站点中的大多数静态资产很少发生变化,因此缓存它们可以显著减轻服务器的负担。想想你公司徽标的图像,这种变化的频率是多少?如果每个页面都显示您的徽标,那么在浏览器中缓存图像非常有意义。

但如果它真的改变了会发生什么?您希望确保用户在资产可用时立即获得更新的资产。如果与站点关联的Java脚本文件发生更改,则可能是更关键的要求。如果用户最终使用了你的JavaScript缓存版本,他们可能会看到奇怪的错误,或者你的应用程序对他们来说可能是错误的。

这个难题在Web开发中很常见,处理它的最常见方法之一是使用缓存破坏查询字符串。

定义:缓存破坏查询字符串将查询参数添加到URL,例如?v=1。浏览器将缓存响应,并将其用于对URL的后续请求。当资源更改时,查询字符串也会更改,例如更改为?v=2。浏览器会将此视为对新资源的请求,并发出新的请求。

这种方法的最大问题是,它需要您在每次图像、CSS或JavaScript文件更改时更新URL。这是一个手动步骤,需要更新引用资源的每个位置,因此难免会出错。标记救援人员!当您向应用程序中添加<script>、<img>或<link>元素时,可以使用Tag Helpers自动生成缓存破坏查询字符串:

<script src="~/js/site.js" asp-append-version="true"></script>

asp-append-version属性将加载被引用的文件,并根据其内容生成唯一的哈希。然后将其作为唯一查询字符串附加到资源URL:

<script src="/js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe"></script>

由于该值是文件内容的哈希值,因此只要文件未被修改,它将保持不变,因此文件将被缓存在用户的浏览器中。但如果文件被修改,内容的哈希值将发生变化,查询字符串也会发生变化。这确保了浏览器

由于该值是文件内容的哈希值,因此只要文件未被修改,它将保持不变,因此文件将被缓存在用户的浏览器中。但如果文件被修改,内容的哈希值将发生变化,查询字符串也会发生变化。这可以确保浏览器始终为您的应用程序提供最新的文件,而无需担心在更改文件时手动更新每个URL。

到目前为止,在本章中,您已经了解了如何将Tag Helpers用于表单、链接生成和缓存破坏。还可以使用标记辅助对象根据当前环境有条件地渲染不同的标记。这使用了一种您尚未见过的技术,其中标记助手被声明为一个完全独立的元素。

8.5 使用环境标记帮助程序的条件标记

在许多情况下,您希望在Razor模板中呈现不同的HTML,这取决于您的网站是在开发环境中运行还是在生产环境中运行。例如,在开发中,您通常希望JavaScript和CSS资产冗长且易于阅读,但在生产中,您需要处理这些文件以使其尽可能小。另一个例子可能是,当应用程序在测试环境中运行时,希望将横幅应用于应用程序,当您转到生产环境时,横幅将被删除,如图8.11所示。

图8.11 每当您在测试环境中运行时,都会显示警告横幅,以便于与生产环境区分开来。

注:您将在第11章中了解如何为多个环境配置应用程序。

您已经了解了如何使用C#将if语句添加到标记中,因此当当前环境具有给定值时,使用此技术将额外的div添加到标记是完全可能的。如果我们假设env变量包含当前环境,那么可以使用如下内容:

@if(env == "Testing" || env == "Staging")
{
  <div class="warning">You are currently on a testing environment</div>
}

这没有什么错,但更好的方法是使用标记帮助器范例来保持标记的干净和易读。幸运的是,ASP.NET Core附带了EnvironmentTagHelper,可以使用它以更清晰的方式实现相同的结果:

<environment include="Testing,Staging">
  <div class="warning">You are currently on a testing environment</div>
</environment>

这个Tag Helper与您以前见过的其他标记有点不同。整个元素不是使用asp属性扩充现有的HTML元素,而是Tag Helper。这个标记助手完全负责生成标记,并使用一个属性来配置标记。

从功能上讲,这个Tag Helper与C#标记相同(尽管目前我已经解释了如何找到env变量),但它在功能上比C#标记更具声明性。显然,您可以自由使用这两种方法,但就我个人而言,我喜欢Tag Helpers的类似HTML的特性。

我们已经到了关于标记帮助程序的本章的结尾,通过它,我们第一次看到了构建向用户显示HTML的传统Web应用程序。在本书的最后一部分,我们将重新访问Razor模板,您将学习如何构建自定义组件,如自定义标记帮助程序和视图组件。目前,您已经拥有构建复杂Razor布局所需的一切,自定义组件可以帮助您整理代码。

本书的第1部分简要介绍了如何使用ASP.NET Core构建RazorPage应用程序。现在,您已经具备了开始制作简单ASP.NET Core应用程序的基本构建块。在本书的第二部分中,我将向您展示构建完整应用程序所需了解的一些附加功能。但在开始之前,我将用一章讨论构建Web API。

我之前提到过WebAPI方法,在这种方法中,应用程序使用MVC框架提供数据,但它不会返回用户友好的HTML,而是返回机器友好的JSON。在下一章中,您将了解为什么以及如何构建Web API,看看为API设计的替代路由系统,并了解如何生成请求的JSON响应。

总结

  • 使用Tag Helpers,您可以将数据模型绑定到HTML元素,从而更容易生成动态HTML,同时保持编辑器友好。
  • 与Razor一样,标记帮助程序仅用于HTML的服务器端呈现。您不能在前端框架(如Angular或React)中直接使用它们。
  • 标记帮助程序可以是独立的元素,也可以使用属性附加到现有的HTML。这使您既可以自定义HTML元素,也可以添加全新的元素。
  • 标记助手可以自定义附加到的元素,添加其他属性,以及自定义如何将其呈现为HTML。这可以大大减少需要编写的标记数量。
  • 标记帮助程序可以在单个元素上显示多个属性。这使得配置Tag Helper更容易,因为您可以设置多个单独的值。
  • 您可以将asp页面和asp页面处理程序属性添加到<form>元素,以使用RazorPages的URL生成功能设置操作URL。
  • 您可以使用asproute-*属性指定在使用FormTagHelper进行路由时使用的路由值。这些值用于构建最终URL或作为查询数据传递。
  • Form Tag Helper还生成一个隐藏字段,可用于防止CSRF攻击。这是自动添加的,是一项重要的安全措施。
  • 您可以使用aspfor将标签标记助手附加到<Label>。它基于[Display]Data Anno-tations属性和PageModel属性名称生成一个适当的for属性和标题。
  • Input Tag Helper根据绑定属性的type和应用于它的任何DataAnnotations将<Input>元素的type属性设置为适当的值。它还生成客户端验证所需的数据val-*属性。这大大减少了需要编写的HTML代码量。
  • 要启用客户端验证,必须将必要的JavaScript文件添加到视图中,以进行jQuery验证和非侵入性验证。
  • Select Tag Helper可以使用asp for和asp items属性生成下拉<Select>元素以及列表框。要生成multiselect<select>元素,请将该元素绑定到视图模型上的IEnumerable属性。您可以使用这些方法生成几种不同样式的选择框。
  • 在的asp中提供的项必须是IEnumerable<SelectListItem>。如果尝试绑定另一个类型,Razor视图中将出现编译时错误。
  • 您可以使用Html.GetEnumSelectList<TEnum>()帮助器方法为枚举TEnum生成IEnumerable<SelectListItem>。这样就不用自己编写映射代码了。
  • 如果asp中提供的项在Group属性上具有关联的SelectListGroup,则Select Tag Helper将生成<optgroup>元素。组可用于分隔选择列表中的项目。
  • 添加到Razor标记中的任何额外的<option>元素都将传递给最终的HTML。您可以使用这些附加元素轻松地向<select>元素添加“no selection”选项。
  • ValidationMessageTagHelper用于呈现给定属性的客户端和服务器端验证错误消息。当元素出现错误时,这会向用户提供重要的反馈。使用asp validation for属性将validation Message Tag Helper附加到<span>。
  • Validation Summary Tag Helper用于显示模型以及各个属性的验证错误。您可以使用模型级属性来显示不适用于一个属性的其他验证。使用asp validation summary属性将validation summary Tag Helper附加到<div>。
  • 您可以使用Anchor Tag Helper生成<a>URL。这个助手使用路由来使用asp页面、asp页面处理程序和asp route-*属性生成href URL,从而为您提供路由的全部功能。
  • 您可以将aspappend-version属性添加到<link>、<script>和<img>元素,以根据文件内容提供缓存破坏功能。这可以确保用户出于性能原因缓存文件,但始终可以获得最新版本的文件。
  • 您可以使用环境标记助手根据应用程序的当前执行环境有条件地呈现不同的HTML。如果您愿意,可以使用它在不同的环境中呈现完全不同的HTML。