ASP.NET Core中的TagHelper及其用法

文章目录

  • TagHelper
  • 导入内置的TagHelper
    • 使用TagHelper生成Link链接
    • TagHelper中的Link标签
  • 为什么要使用TagHelper
    • 使用TagHelper的优势
  • Image TagHelper
    • 浏览器缓存
    • 禁用浏览器缓存
    • HTTP状态码的200与302
    • ASP.NET Core中的Image TagHelper
  • ASP.NET Core中的Environment TagHelper
    • 设置应用程序环境的名称
    • 如果CDN“挂了”,怎么办
  • 使用Bootstrap给项目添加导航菜单
    • 布局页面_Layout.cshtml的代码
  • Form TagHelpers 提交学生信息
    • 场景描述
    • Form TagHelper
    • Input TagHelper
    • Label TagHelper
    • Select TagHelper
    • Create.cshtml中基本的HTML代码
    • Bootstrap优化后的Create.cshtml的代码

TagHelper

标记帮助程序(TagHelper)是ASP.NET Core中的新增功能。

​ 首先通过一个例子来理解TagHelper及其用途。

​ TagHelper是服务器端组件。它们在服务器上运行,并在Razor文件中创建和渲染HTML元素。如果对以前版本的ASP.NET Core MVC有一定了解,那么读者可能也知道HTML TagHelper。TagHelper类似于HTML TagHelper,ASP.NET Core有许多内置的TagHelper用于常见任务,比如生成链接、创建表单和加载数据等。TagHelper的出现可帮助提高生产效率,并生成更稳定的 、可靠和可维护的代码。

导入内置的TagHelper

​ 要在整个应用程序中的所有视图使用内置TagHelper,需要在_ViewImports.cshtml文件导入TagHelper。要导入TagHelper,我们使用@addTagHelper指令。

@addTagHelper *.Microsoft.AspNetCore.Mvc.TagHelpers

​ 通配符*表示我们要导入MVC中所有的TagHelper,而Microsoft.AspNetCore.Mvc.TagHelpers则是内置TagHelper的组件位置。

使用TagHelper生成Link链接

​ 假设要查看指定学生的详细信息,则要生成以下超链接。数字5是我们要查看其详细信息的学生的ID。

/home/details/5

​ 我们可以通过多种方式在Razor视图中实现该效果。

  1. 手动生成链接
@foreach (var student in Model)
{
    <a href="/home/details/@student.ID">查看</a>
}
  1. 使用HTML TagHelper
@Html.ActionLink("查看","details",new {ID = student.ID})
    生成结果Link元素<a href="/home/details/5">查看</a>或者@Url.Action("details","home",new{ID=student.Id})

​ 生成的结果:/home/details/5。

  1. 使用TagHelper
<a asp-controller="home" asp-action="details" asp-route-id="@student.ID" >查看a>,
生成结果<a href="/Home/details/5">查看a>

TagHelper中的Link标签

​ TagHelper中的Link标签通过添加新属性来增强标准的HTML标签,以下TagHelper均可以增强Link标签的href属性值。

asp-controller
asp-action
asp-route-{value}

​ 正如名称所表示的那样,asp-controller指定控制器名称,而asp-action指定要包含在生成的href属性值中的操作方法名称asp-route-{value}属性用于在生成的href中包含路由数据属性值。{value}可以替换为路由参数,比如id。参考以下代码:

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看a>

​ 生成结果: 查看

​ 从下面的代码中可以看出,手动生成的链接比使用HTMLHelper或TagHelper要容易得多。

<a href="/home/details/@student.ID">查看a>

​ 读者可能产生一个疑问:为什么我们要使用TagHelper或HTML Helper来生成这些链接,而不是手动生成?我们将在下文回答这个问题。

为什么要使用TagHelper

​ 让我们通过一个简单的例子来理解TagHelper的优势。

​ 假设我们想要查看特定的学生的详细信息,则需要生成超链接,比如学生ID为5的详细信息。

/home/details/5

​ 我们可以通过手动编写,如下:

<a href="/home/details/@student.ID">查看a>

​ 也可以使用Link链接的TagHelper,代码如下:

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看a>

使用TagHelper的优势

​ TagHelper是根据应用程序的路由模板生成的链接,这意味着如果我们更改路由模板,则TagHelper生成的链接会针对路由模板所做的更改自动修改和适配,让生成的链接正常工作。

​ 而如果我们手动硬编码了URL,则当应用程序路由模块发生变化时,就必须在很多地方更改代码,这样效率并不高。

​ 可以通过一个例子来理解这一点。

app.UseEndpoints(endpoints=>
                 {
                     endpoints.MapControllerRoute(
                         name:"default",
                         pattern:"{controller=Home}/{action=Index}/{id?}"
                     );
                 });

​ 以下代码没有用TagHelper,而是对URL路径进行硬编码。

<a href="/home/details/@student.ID">查看a>

以下代码是使用元素的TagHelper完成的。

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看a>

​ 请注意,我们没有针对URL路径进行硬编码,只指定控制器和操作方法的名称,以及路由参数及其值。在服务器上执行TagHelper时,它们会查看路由模板并自动生成正确的URL。

​ 上述两种方法都会生成正确的URL路径(/home/details/5),它适用于当前路由模板({controller=Home}/{action=Index}/{id?})。

​ 现在让我们改变路由模板,代码如下。请注意,在URL中有字符串pragim

app.UseEndpoints(endpoints=>
                 {
                     endpoint.MapControllerRoute(
                     	name:"deafault",
                         pattern:"pragim/{controller=Home}/{action=Index}/{id?}"
                     );
                 });

​ 请注意,不要忘记删除HomeController中属性路由的属性,否则项目还是会正常进入Home/Index的路径中。当读者运行项目发生404错误的时候,记得添加pragim域信息和正确的URL访问路径http://localhost:2051/pragim。编译并运行项目,使用TagHelper生成的代码是正确的链接。

<a href="/pragim/home/details/1">查看a>。 
//其中未使用TagHelper的代码则没有变化,缺少URL路径“/pragim”
<a href="/home/details/1">查看a>

​ 我们还有其他TagHelper,它可以生成表单。将此表单发回服务器时,将自动处理发布的值并显示相关的验证信息。如果没有这些TagHelper,我们将不得不编写大量自定义代码来实现相同的功能。

​ 如果此时读者觉得没有多大意义,请耐下心来。我们会在后面创建学生信息的时候讨论表单的TagHelper。

Image TagHelper

​ 在开始说Image标记帮助程序的好处之前,我们先验证一下普通元素的问题。

​ 准备好两个图片文件,一个名为noimage.png,另一个名为noimage1.png,把它们存储在wwwroot/images文件夹中。现在正常运行项目,如图所示。

ASP.NET Core中的TagHelper及其用法_第1张图片

​ 接下来回到项目中,将noimage.png重命名为noimage2.png。然后将noimage1.png重命名为noimage.png。再次刷新页面会发现没有变化,打开开发者工具可以发现,返回的HTTP Code:200 OK(from memmory cache)是从缓存中得到的,如图所示。

ASP.NET Core中的TagHelper及其用法_第2张图片

​ 这样带来的问题是用户会认为我们的程序出问题了,那么怎么解决?

浏览器缓存

​ 当访问网页时,大多数浏览器会缓存该网页的图片,这样再次访问该页面时,浏览器就不用从Web服务器下载相同的图片,而是从缓存中提取。在大多数情况下,这不是问题,因为图片不会经常发生改变,但是这对开发人员来说相当不友好。

禁用浏览器缓存

​ 由于某种原因,如果读者不希望浏览使用器缓存,则可以禁用它。比如,要在Google Chrome中禁用缓存,步骤如下:

  • 按F12,启动Browser Developer Tools
  • 单击NetWork选项卡。
  • 选中DIsable cache复选框。如图所示。

ASP.NET Core中的TagHelper及其用法_第3张图片

​ 禁用浏览器缓存后,会带来一个明显的问题,那就是每次访问该页面时都必须从服务器下载图片,要记得平时关闭禁用缓存。

​ 现在刷新浏览器,新的图片就会加载出来了。

HTTP状态码的200与302

​ HTTP状态码是用于表示网页服务器HTTP响应状态的3位数字代码。状态码的第一个数字代表响应的5中状态之一,这里我们只介绍涉及的3xx2xx系列。

2xx系列代表请求已成功被服务器接收、理解并接受,这系列中常见的200状态码和201状态码。

  • 200状态码:表示请求已成功,请求所希望的响应头或数据体将随此响应返回。
  • 201状态码:表示请求成功,服务器创建了新的资源,并且其URI已经随Location请求头信息返回。假如需要的资源无法及时建立的话,应当返回202Accepted。

3xxx系列代表需要客户端采取进一步的操作才能完成请求,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。这系列中常见的有301状态码和302状态码。

  • 301状态码:被请求的资源已永久移动到新位置。服务器返回此响应(对GET请求或HEAD请求的响应)时,会自动将请求者转到新位置。
  • 302状态码:请求的资源临时从不同URI响应请求,但请求者应继续使用原有位置来进行以后的请求。

简单来说:3xx系列表示请求的是客户端,而2xx系列表示请求的是服务器端。

ASP.NET Core中的Image TagHelper

​ 从性能角度来看,只有在服务器上更改了图片才能对其进行下载。如果图片未更改,请使用浏览器中缓存的照片。这意味着我们将拥有两全其美的优势。

​ Image TagHelper可以帮助我们实现这一效果。要使用Image TagHelper,请包含asp-append-version属性并将其设置为true

​ 现在我们回到项目中,打开Index.cshtmlDetails.cshtml并对它们进行修改,代码如下。

<img src="~/images/noimgage.png" asp-append-verison="true"/>

​ Image TagHelper增强了img标签属性,为静态图像文件提供了缓存清楚行为,通过散列计算生成唯一的散列值并将其附加到图片的URL中。唯一的散列值会提示客户端(或某些代理)从服务器重新加载图片,而不是从浏览器的缓存中重新加载。以下是生成的代码。

ASP.NET Core中的TagHelper及其用法_第4张图片

​ 只有当每次服务器上的图片更改时,才会计算并缓存新的散列值。如果图片未更改,则不会重新计算散列值。使用此散列值,浏览器会跟踪服务器上的图片内容是否已更改。使用Image TagHelper可以帮助我们解决很多由潜在因素造成的问题。

ASP.NET Core中的Environment TagHelper

​ 我们在ASP.NET Core应用程序开发过程中使用了Bootstrap。为了便于调试,希望在本地开发计算机(在开发环境中)通过应用程序加载没有压缩的Bootstrap的CSS文件(bootstrap.css)。而在Staging、Production或除Development环境以外的任何其他环境中,希望应用程序能从CDN(内容分发网络)加载压缩后的Bootstrap的CSS文件(bootstrap.min.css)以获得更好的性能。

​ 但是,如果CDN出现故障或者出于某种原因,当应用程序无法访问CDN的时候,我们希望应用程序不要访问CDN,并从应用程序Web服务器加载压缩后的Bootstrap文件。

​ 很多开发框架都有这种功能,现在我们可以使用ASP.NET Core Environment TagHelper轻松实现这一点。在我们理解Environment TagHelper之前,我们先来了解如何设置应用程序环境的名称。

设置应用程序环境的名称

​ Environment TagHelper支持根据应用程序环境呈现不同的内容,它使用ASPNETCORE_ENVIRONMENT变量的值作为环境的名称。

​ 如果应用程序时Development ,则此示例加载没有压缩的bootstrap.css文件,代码如下:

<environment include="Development">
    	<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
environment>

​ 如果应用程序环境是Staging或者Production,则此示例从CDN加载压缩后的bootstrap.min.css文件,代码如下。

<environment include="Staging,Production">
   
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
environment>

​ include属性接受将单个环境名称以逗号分隔的形式生成列表。在Environment TagHelper中还有exclude属性,当托管环境与exclude属性值中列出的环境名称不匹配时,将呈现标签中的内容。

​ 如果应用程序不是Development,则从此示例从CDN加载压缩后的bootstrap.min.css文件,代码如下:

<environment exclude="Development">
        
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"/>
    environment>

元素中的integrity属性用于检查子资源完整性。Subresource Integrity(SRI)是一种安全功能,允许浏览器检查被检索的文件是否被恶意更改。当浏览器下载文件时,它会重新计算散列值并将其与完整性属性散列值进行比较。如果散列值匹配,则浏览器允许下载文件,否则将被阻止。

如果CDN“挂了”,怎么办

​ 如果CDN出现故障或出于某种原因应用程序无法访问CDN,则希望应用程序从应用程序Web服务求加载压缩后的Bootstrap文件,代码如下。

 <environment include="Development">
        <link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
    environment>

    <environment exclude="Development">
        
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" asp-fallback-href="~/lib/twitter-bootstrap/css/bootstrap.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="positon" asp-fallback-test-value="absolute" asp-suppress-fallback-integrity="true" />
    environment>

​ 如果应用程序环境是Development,则从应用程序Web服务器加载没有压缩的bootstrap.css文件;如果应用程序环境不是Development,则从CDN加载缩小的bootstrap.min.css文件。

​ 使用asp-fallback-href属性指定回退源。这意味着,如果CDN关闭,则应用程序将回退并从应用程序Web服务器加载缩小的Bootstrap文件。

​ 以下3个属性及其相关值用于检查CDN是否关闭。

  • asp-fallback-test-calss="sr-only"
  • asp-fallback-test-propery="position"
  • asp-fallback-test-value="absolute"

当然,这会设计计算散列值,并将其与文件的完整性属性散列值进行比较。对于大多数应用程序,CDN失效的时候都是回退到它们自己的服务器,方法是将asp-suppress-fallback-integrity属性设置为true,当然读者也可以选择关闭从本地服务器下载的文件完整性检查。

使用Bootstrap给项目添加导航菜单

​ ❗请注意,Bootstrap的所有Javascript插件都依赖于jQuery,因此jQuery必须在Bootstrap之前引入。读者可以使用Libman管理工具下载jQuery,也可前去jQuery官网下载。

布局页面_Layout.cshtml的代码



<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <environment include="Development">
        <link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
        <script src="~/lib/jquery/jquery.js">script>
        <script src="~/lib/twitter-bootstrap/js/bootstrap.js">script>
    environment>

    <environment exclude="Development">
        
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" asp-fallback-href="~/lib/twitter-bootstrap/css/bootstrap.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="positon" asp-fallback-test-value="absolute" asp-suppress-fallback-integrity="true" />
    environment>

    <link href="~/css/site.css" rel="stylesheet" />
    <title>@ViewBag.Titletitle>
head>
<body>
    <div class="container">
        <nav class="navbar navbar-expand-sm bg-dark navbar-dark">
            <a class="navbar-brand" asp-controller="home" asp-action="index">
                <img src="~/images/student.png" width="30" height="30" />
            a>
            <button class="navbar-toggler"
                    type="button"
                    data-toggle="collapse"
                    data-target="#collapsibleNavbar">
                <span class="navbar-toggler-icon">span>
            button>
            <div class="collapse navbar-collapse" id="collapsibleNavbar">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" asp-controller="home" asp-action="index">列表a>
                    li>
                    <li class="nav-item">
                        <a class="nav-link" asp-controller="home" asp-action="create">创建a>
                    li>
                ul>
            div>
        nav>
        @RenderBody()
    div>

   
    @if (IsSectionDefined("Scripts"))
    {@RenderSection("Scripts", required: false)}
body>
html>

​ 注意,对于非开发环境(Staging 、Production等),我们没有使用所需的元素来从CDN加载所需的Jquery和Bootstrap Javascript文件。

​ 请注意,按钮(查看、编辑、删除)是相互连接在一起的,我们要在这些按钮之间包含边框,需使用Bootstrap提供的边距类(m-1、m-2等)。在类名中,m代表边距,数字1、2等代表所需空间的大小。

​ 在Index.cshtml修改\元素,使其包含m-1

ASP.NET Core中的TagHelper及其用法_第5张图片

Form TagHelpers 提交学生信息

场景描述

我们在ASP.NET Core中使用以下常用的TagHelpers创建表单。

  • Form TagHelper。
  • Label TagHelper。
  • Input TagHelper。
  • Selece TagHelper。
  • Textarea TagHelper。
  • Validation TagHelper。

我们希望使用Form TagHelpers创建表单,并使用Bootstrap对其进行样式设置,完成创建学生信息。

​ 我们在HomeController中添加如下代码。

 public IActionResult  Create()
        {
            return View();
        }

然后在路径为Views/Homes/的文件夹中添加视图Create.cshtml

Form TagHelper

​ 要创建表单可以使用Form TagHelper。需要注意的是,我们实际是使用asp-controllerasp-action TagHelper。这两个TagHelper指定控制器并在提交表单时将表单数据发布到指定的操作方法上。我们希望在提交表单时发出POST请求,因此将method属性设置为post。

<form asp-controller="home" asp-action="create" method="post">
form>

​ 从客户端浏览器上呈现表单时,上面的代码会生成以下HTML代码。正如读者在提交表单时从生成的HTML代码中看到的那样,它将被发布到HomeController的Index()方法中,编译后打开源代码可以看到渲染出来的HTML代码。

<form method="post" action="/home/create">
    
form>

​ 请注意,默认情况下在提交表单时,它将被发布到当前页面表单的控制器的操作方法中。这意味着,即使我们没有使用asp-controllerasp-action TagHelper指定对应的控制器和操作方法,表单仍然被发布到HomeController的Index()方法中,但是建议写的时候还是显示声明。

Input TagHelper

​ Input TagHelper将HTML中的元素绑定到Razor视图中的模型表达式。

​ 在我们的例子中想要设计一个表单来创建新学生信息。因此,Create.cshtml视图的模型是Student类,需要使用@model 指令,即@model Student

​ 为了获取学生姓名,我们需要一个文本框并将其绑定到Student模型类的Name属性。我们使用asp-for TagHelper将input的属性值设置为Student模型类的name属性。

​ 请注意,Visual Studio会提供智能提示。如果在Student类上将属性名称Name更改为FullName,但不更改分配给的TagHelper的值,则会出现编译器错误。

<input asp-for="Name" />

​ 上面的代码会生成一个带有id和name属性的元素。请注意,它们的值均为Name。

<input type="text" id="Name" name="Name" value="" />

​ name属性是必须的,它用于在提交表单时将输入元素的值映射到模型类的对应属性。这是通过ASP.NET Core中称为模型绑定的过程完成的。

Label TagHelper

​ Label TagHelper会生成带有for属性的标签。属性链接与和它相关的输入元素的标签进行绑定,代码如下。

<label asp-for="Name">label>    <input asp-for="Name" />

上面的代码生成以下HTML代码:

<label for="Name">Namelabel>
<input type="text" id="Name" name="Name" value="" />

​ Label标签链接到input标签,因为这两种标签的属性和input标签的id属性具有相同的值(Name)。

​ 同样,以下代码生成

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

Select TagHelper

​ Select TagHelper会生成select标签及其关联的元素。在我们的例子中需要通过select显示主修科目列表。最后,我们需要一个select标签和一个带有主修科目选项列表的元素,如下所示。

<label for="Major">主修科目label>
<select id="Major" name="Major">
    <option value="0">计科option>
    <option value="1">信安option>
    <option value="2">网工option>
select>

​ 主修科目的元素的选项内容可以像上面的示例中那样进行硬编码,也可以来自枚举或数据库表。我们还没有连接数据库,因此,对于我们的示例可以从枚举中获取选项。

​ 我们在Models/EnumTypes的文件夹中创建一个MajorEnum.cs枚举类。

 public enum EnumTypes
    {
        None,
        FirstGrade,
        SecondGrade,
        GradeThree
    }

​ 修改Models文件夹中Student.cs文件的代码,将Major属性数据类型改为MajorEnum。在Create.cshtml视图中添加以下代码。

<label asp-for="Major">label>
<select asp-for="Major" asp-items="Html.GetEnumSelectList()">
select>

​ 请注意,我们使用asp-items属性值帮助程序和Html.GetEnumsSelectList()获取