ASP.NET Core 内置的Tag Helpers

ASP.NET Core 框架内置了大量的Tag Helpers,以asp-*前缀开始,他们用于增强表单,验证消息,设计布局等,在这节中我们将继续讨论内置的Tag Helpers,例如表单控件,输入控件,选择控件,标签控件,锚点标签,文本控件,CSS,JS 和Cache

1 Form帮助标签

ASP.NET Core表单控件用来增强原始HTML表单的健壮性和高效性,当业务发生变化时这些表单的可维护性很高,这些标记为表单生成action属性以及隐藏的请求验证令牌,以防止跨站点伪造请求

下面给与了表单常用的帮助标签

方法
描述

asp-controller

根据应用程序的路由指定目标Controller,如果省略,使用当前视图文件所在的控制器

asp-action

根据应用程序的路由指定目标Action方法,如果省略,使用视图文件当前Action方法

asp-route-*

指定url额外的段,例如 asp-route-id 使用提供id段的值

asp-route

通过指定路由的名称生成action属性

asp-area

指定目标区域的名称

asp-antiforgery

生成一个隐藏的请求验证令牌用来防止跨站点请求攻击,经常和[ValidateAntiForgeryToken]特性一起使用,[ValidateAntiForgeryToken]使用在HTTP Post方法上

如果我们的应用程序只有一个路由定义在Programe.cs类中

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

现在我们使用帮助标签来创建表单

<form method="post" asp-controller="Home" asp-action="Create">
...
</form>

在这种情况下表单的action方法将生成/Home/Create,我们检查一下表单中生成的HTML

<form method="post" action="/Home/Create">
...
</form>

在应用程序中的目录下Views->Home文件夹下创建一个新的视图文件,名字为Create.cshtml, 添加下面代码:

@model Product
@{
    ViewData["Title"] = "新增";
}
<form method="post" asp-controller="Home" ,asp-action="Create">
    <div class="mb-3 row">
        <label class="col-sm-1 control-label" for="Name">名称:</label>
        <div class="col-sm-11">
            <input class="form-control" name="name" />
        </div>
    </div>
    <div class="mb-3 row">
        <label class="col-sm-1 control-label" for="Price">价格</label>
        <div class="col-sm-11">
            <input class="form-control" name="price" />
        </div>
    </div>
    <div class="mb-3 row">
        <label class="col-sm-1 control-label" for="Quantity">数量</label>
        <div class="col-sm-11">
            <input class="form-control" name="quantity" />
        </div>
    </div>
    <div class="col-sm-11 offset-sm-1">
        <button type="submit" class="btn btn-primary">新增</button>
    </div>
</form>

我们视图中创建一个form标签,使用asp-controller="Home"和asp-action="Create"帮助标签创建html表单的action属性

表单的method是post,当提交表单时Create的方法被调用,在HomeController中添加2个Create方法,一个是HTTPGet另外一个是HttpPost

这两个Action方法的代码如下:

public IActionResult Create()
{
    return View();
}
[HttpPost]
public IActionResult Create(Product product)
{
    return RedirectToAction("Index");
}

我们在label元素上使用for属性,用来绑定label元素,输入控件的name属性分别被赋值为-name,price&quantity,这些名称是Product.cs类的属性,我们通过使用控件的名称来绑定action方法的参数

运行应用程序,你将会看到一个表单,在浏览器中检查表单元素并且你将看到action特性被创建为/Home/Create

图片展示如下:

87af26d8a6f9a9eea1e9f63fc2f3595d.png

提交表单新的产品将添加到repository,将会跳转到Index视图在产品列表显示所有的产品

注意:表单所在的Create视图位于HomeController中,对应的Action方法为Create,因此我们也不需要应用asp-action和asp-controller帮助标签

下面代码也能工作:

<form method="post">
....
</form>

1.1 asp-antiforgery

asp-antiforgery生成一个隐藏的请求验证令牌,这个令牌为antiforgerytoken,为了防止CSRF攻击,当你在你的表单上使用这个特性,ASP.NET Core做两件事:

1 在表单的隐藏域中添加一个安全的token

2 在响应添加一个cookie

如果表单中包含Cookie和隐藏的值,应用程序将处理这个请求,恶意站点不能访问,因此阻止了CSRF

为了使用这个特性,在表单元素中添加帮助标签asp-antiforgery="true", 并且在对应的请求方法上添加[ValidateAntiForgeryToken]特性

@model Product
@{
    ViewData["Title"] = "Create";
}
<form method="post" asp-controller="Home" asp-action="Create" asp-antiforgery="true">
    // removed for clarity
</form>

在表单的Create视图中添加asp-antiforgery属性:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Product product)
{
    return RedirectToAction("Index");
}

运行应用程序并且检查Create视图的HTML代码,你会在form元素内发现一个隐藏域并且它包含一个token值,如下所示:

ec7b5f9bb6a0874a19b08e62ccd2f150.png

现在打开Developer Tools, 进入Application页,接着在左边点击Cookies,你将会看到anti-forgery cookie,它将被一块发送到控制器

c837076abde8db4ff8127415d9df1d52.png

[ValidateAntiForgeryToken]特性将自动验证这个cookie和token

2 Label帮助标签

Label帮助标签用来设置HTML中的Label,我们在label上添加asp-for属性,在label标签上创建一个for属性,为了测试我们在为Create视图中的Label添加asp-for属性

运行应用程序,打开浏览器检查生成html源码

f123d322636a95bf93e23df40e27cea4.png

3 Input帮助标签

ASP.NET Core Input帮助标签用来将输入元素绑定到模型表达式-asp-for="expression",当我们在input输入控件中添加asp-for属性,input控件会使用模型表达式设置name,id,type和value属性的值,我们修改Create视图中的Input元素for修改为asp-for

运行应用程序并且查看HTML源码,我们发现input输入框包含了id,name,type,value四个属性

aafb45a009a25f9a8673898d7f60ac99.png

你会发现Name和Price输入框的type是Text,但是Quantity输入框的类型是number,这是因为ASP.NET Core基于模型属性类型给HTML控件提供type的值

下面表格告诉我们不同类型的值是如何对应的:

模型类型

输入框类型

byte, sbyte, int, uint, short, ushort, long, ulong

Number

float, double, decimal

text

string

text

bool

checkbox

DateTime

datetime

4 Select帮助标签

Select帮助标签用来指定模型属性并且针对下拉框元素可选

1 asp-for 用模型属性名字设置为Select元素的id和name属性

2 asp-items 给Select元素提供可选的值

我们把Create视图中quantity字段从输入框修改为选择框:

10de866fb6fd312e39a4fb6e93eb84eb.png

现在我们检查一下在浏览器中生成的HTML代码,我们看到把id和value的值设置为Product.cs类的Quantity属性,代码如下:

01e24d988b58565c3e9fab818f2cf13c.png

ASP.NET Core框架非常智能,选择控件能够自动选择默认值,为了了解它,添加Edit方法在Home控制器中,这个方法将从仓储中返回最后添加的记录,方法代码如下:

public ViewResult Edit() => View("Create", _repository.Products.Last());

进入编辑页面的地址https://localhost:7182/Home/Edit,我们能清楚看到最后一条记录时400被自动选择在选择控件中

79af299bac2ce6788ff3e37a8a7e06aa.png

检查生成的HTML源码,注意selected特性应用到了包含400值的选项,代码如下:

ebf4aebe99140bb39d9de6f6fc0a0297.png

4.1 asp-items 特性

asp-items 特性使用指定下拉框列表中的元素,它用来帮助我们从数据源生成下拉框列表中的元素,修改Create视图下拉框代码,现在使用asp-items特性:

<select class="form-control" asp-for="Quantity" asp-items="ViewBag.Quantity">
    <option disabled selected value="">Select Quantity</option>
</select>

我们指定ViewBag.Quantity作为asp-items特性的值,ViewBag将包含一个SelectList对象将作为下拉框中的元素呈现,现在修改Create和Edit方法

using AspNetCore.BuiltInTagHelpers.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Diagnostics;
using static AspNetCore.BuiltInTagHelpers.Models.Repository;
namespace AspNetCore.BuiltInTagHelpers.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;


        private readonly IRepository _repository;
        public HomeController(IRepository repository,
                              ILogger<HomeController> logger)
        {
            _repository = repository;
            _logger = logger;
        }
        public ViewResult Edit()
        {
            ViewBag.Quantity = new SelectList(_repository.Products.Select(p => p.Quantity).Distinct());
            return View("Create", _repository.Products.Last());
        }
        public IActionResult Index()
        {
            return View(_repository.Products);
        }
        public IActionResult Create()
        {
            ViewBag.Quantity = new SelectList(_repository.Products.Select(p => p.Quantity).Distinct());
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Create(Product product)
        {
            _repository.AddProduct(product);
            return RedirectToAction("Index");
        }
        public IActionResult Privacy()
        {
            return View();
        }
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

ViewBag.Quantity 属性设置为SelectList 对象,使用仓储Quantity值来填充该对象,经过这么一番修改,我们实现了动态选择

SelectList对象位于Microsoft.AspNetCore.Mvc.Rendering命名空间

运行应用程序,请求 https://localhost:7076/Home/Create 或者https://localhost:7076/Home/Edit 地址,这次你会发现可选元素被创建在ViewBag.Quantity数据源

5 Cache帮助标签

Cache帮助标签使用缓存内容用来帮助提高应用程序的性能,你可以将内容添加到缓存标签内部:

<cache> Some Content </cache>

进入_Layout.cshtml文件并且添加cache元素用来缓存当前时间:

<div class="container">
        <main role="main" class="pb-3">
            <div class="bg-info text-warning">
                <cache>
                    Date Time: @DateTime.Now.ToString("HH:mm:ss")
                </cache>
            </div>
            @RenderBody()
        </main>
    </div>

现在运行应用程序,你将会看到当前时间显示在页面顶部,如下图所示:

f4d86e8cc20dbd2c026c61351b4e0cbd.png

现在刷新页面并且我们将看到时间在小时,分钟,秒没有任何变化,这是因为时间被缓存了

下面缓存标签比较重要的属性:

名称

描述

expires-on

给缓存指定一个过期的绝对时间

expires-after

指定一个缓存过期的相对时间,TimeSpan值

expires-sliding

滑动时间,最后一次使用时间短, 它指定TimeSpan值中缓存过期的滑动时间

vary-by-query

一个查询字符串的键,被用来管理不同版本的缓存

vary-by-cookie

一个cookie名称用来管理不同版本的缓存

vary-by

指定一个key用来管理不同版本的缓存

5.1 expires-after

在_layout.cshtml文件中为缓存代码添加expires-after特性:

<cache expires-after="@TimeSpan.FromSeconds(20)">
    Date Time: @DateTime.Now.ToString("HH:mm:ss")
</cache>

这意味着20秒之后缓存将失效

5.2 expires-on

在_layout.cshtml文件中为缓存代码添加expires-on特性:

<cache expires-on="@DateTime.Parse("2050-01-01")">
   Date Time: @DateTime.Now.ToString("HH:mm:ss")
</cache>

时间被缓存直到2025年

5.3 expires-sliding

在_Layout.cshmtl视图为缓存代码添加expires-sliding特性

<cache expires-sliding="@TimeSpan.FromSeconds(20)" >
    Date Time: @DateTime.Now.ToString("HH:mm:ss")
</cache>

这个缓存将在距离上次使用的20s后过期

为了测试,每两秒加载一次页面,你将会看到相同的时间,等待20秒之后重新加载页面,这时你将看到一个新的时间,这时因为这个缓存在最后一次加载时间20s之后过期

5.4 vary-by

vary-by特性使用指定一个key来管理不同版本的缓存,在_Layout.cshtml视图修改cache元素:

<cache expires-sliding="@TimeSpan.FromSeconds(20)" vary-by="@ViewContext.RouteData.Values["action"]">
    Date Time: @DateTime.Now.ToString("HH:mm:ss")
</cache>

这意味着cache是基于当前action,我们有三个actions-Index,Edit和Create,因此3个版本的缓存将被创建(每个action方法都有一个),expire-sliding特性为每个版本设置滑动时间

6 Anchor帮助标签

Anchor帮助标签使用最广泛的内置帮助标签在ASP.NET Core框架,通过添加新的特性来加强anchor标签,这个特性基于应用程序路由构建anchor标签href

下面表格列举出重要的标签被使用通过anchor 帮助标签

名字

描述

asp-controller

指定url将被定位到的控制器 

asp-action

指定url将被定位到的action

asp-area

指定url将被定位到的area

asp-fragment

指定url段(在#字符后面)

asp-route

指定url将被定位到的路由名称

asp-route-*

指定额外的值针对url 例如asp-route-id="10"为路由段提供了一个id为10的值

进入Index视图并且创建一个链接定位到Create视图:

@{
    ViewData["Title"] = "Home Page";
}
@model IEnumerable<Product>
<div class="container">
    <div class="row mb-3">
        <div class="col-sm-3">
            <a class="btn btn-primary" asp-action="Create">新增</a>
        </div>
        <div class="col-sm-3"></div>
        <div class="col-sm-3"></div>
        <div class="col-sm-3"></div>
    </div>
    <div class="row mb-3">
        <div class="col-sm">
            <table class="table table-bordered align-middle">
                <thead>
                    <tr>
                        <th>名称</th>
                        <th>价格</th>
                        <td>数量</td>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var product in Model)
                    {
                        <tr>
                            <td>@product.Name</td>
                            <td>@product.Price</td>
                            <td>@product.Quantity</td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
    </div>
</div>

这将生成如下链接:

<a class="btn btn-primary" href="/Home/Create">新增</a>

如下图所示

eadf49598f993be27ba44835a4c7da2b.png

我们没有提供asp-controller帮助标签,因为使用了相同的控制器(Index和Create方法在相同的控制器),如果我们使用asp-route-* 特性在anchor帮助标签,如下代码:

<a class="btn btn-primary" asp-action="Create">新增</a>

生成的连接将包含路由id作为url的第三个段

<a class="btn btn-dark" href="/Home/Create/20">新增</a>

7 Javascript帮助标签

JavaScript 帮助标签管理包含和排除Javascript文件从视图文件,使用JavaScript帮助标签使用重要属性:

名称

描述

asp-src-include

指定在视图中包含的JavaScript文件

asp-src-exclude

指定在视图中排除的JavaScript文件

asp-append-version

指定是否把文件版本附加到连接地址,使用 Cache Busting

asp-fallback-src-include

如果使用的CDN出现一些问题时,指定备用的JavaScript文件

asp-fallback-src-exclude

如果使用CDN出现一些问题,指定排除的JavaScript文件

asp-fallback-test

JavaScript代码段,用来测试能否正确加载CDN

我们也可以使用一些列通配符来创建匹配的文件,这些通配符可以配合asp-src-include, asp-src-exclude, asp-fallback-src-include和asp-fallback-src-exclude帮助标签一块使用

常用模式

模式

例子

描述

?

JS/myscript?.js

匹配单个模式排除'/',左边的例子匹配 ‘JS/myscript1.js’, ‘JS/myscriptZ.js’, ‘JS/myscripts.js’等

*

JS/*.js

匹配任何期望的字符/除外,左边给与的例子匹配‘JS/myscript.js’, ‘JS/validate.js’, ‘JS/js123.js’等

**

JS/**.js

匹配任何数量的字符包括/,左边给与的例子匹配‘JS/Validate/myscript.js’,‘JS/jQuery/validate.js’, ‘JS/js123.js’等

这种模式非常有用,可以提供给我们一种基于客户自定义逻辑的方式创建匹配规则

7.1 asp-src-include例子

我们在_Layout.cshmtl中包含bootstrap.js文件,文件位于wwwroot/lib/bootstrap/dist/js/bootstrap.js

如下图所示

4d64647aba19f59c108fa918b74e3b2e.png

我们注意到5个JS文件在相同的文件夹

bootstrap.js
bootstrap.bundle.js
bootstrap.esm.js
bootstrap.js.map
bootstrap.min.js

现在进入_Layout.cshtml 文件并且添加script标签使用asp-src-include属性

bf3528200c431010e7022db0512c91bb.png

运行应用程序并且检查生成的HTML源代码,你将会发现下面JS文件被添加到head节点

a769b85ac7cb05fa6ab4cdd309a6fbaa.png

因为我们在asp-src-include属性中通过使用通配符来包含这些文件,我们可以使用下面代码用来只包含bootstrap.bundle.js文件

<script asp-src-include="lib/bootstrap/**/*bundle.js"></script>

7.2 asp-src-exclude例子

使用asp-src-exclude属性来排除view中的js文件,这次我们在layout文件中使用下面代码,这将从视图中移除所有的‘slim’, ‘min’ & ‘bundle’ 的JavaScript文件

<script asp-src-include="/lib/bootstrap/**/b*.js" asp-src-exclude="**.slim.*,**.min.*,**.bundle.*"></script>

运行应用程序检查生成的HTML源代码,你将发现只有bootstrap.js 和bootstrap.esm.js 

<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.esm.js"></script>

7.3 Busting asp-fragment Attribute

浏览器每次只下载一次图片,css文件和JS文件,并且将他们缓存在本地,当用户访问浏览器,我们将从缓存中读取这些文件,这样避免从服务器端加载文件从而使页面加载更快

假设我们在服务器修改JavaScript文件,客户端仍然缓存老的JS文件,新的JavaScript文件没有加载,因此用户没有看到改变

如何处理这个问题,有一些方法告诉浏览器下载文件当js文件修改完,我们可以使用Cache Busting来解决这个问题

可以使用asp-fragment特性设置Cache Busting,它在JS文件的URL中添加一个checksum查询字符串作为版本号,如果修改JS文件,checksum将会改变,并且浏览器知道现在需要下载最新的js文件从服务器端来重新加载缓存

<script asp-src-include="/lib/bootstrap/**/b*.js"
            asp-src-exclude="**.slim.*,**.min.*,**.bundle.*"
            asp-append-version="true">
</script>

生成的HTML包含如下

41eb67b032c4a15b20db2bccb7eebb1b.png

当浏览器向服务器发出下一个请求时,如果发现服务器上js文件的checksum已经更改

因此,它从服务器下载该文件的最新版本。然后缓存新下载的文件,并在“?”字符后添加新的checksome

8 CDN帮助标签

CDN包含了大量数据服务分部在全球,所有这些数据都保存在网站服务器的静态文件下,如图像、CSS、JS,当用户在浏览器上打开网站时,浏览器不是从网站的服务器请求静态文件,而是从离用户位置最近的数据服务器请求

这减少了网站的加载时间也节省了宽带,如果网站比较小建议使用CDN

asp-fallback-src-include,asp-fallback-src-exclude和asp-fallback-test 指定CDN, 假如有别的因素导致CDN加载jquery失败,在这种情况下我们的网站本地加载JQuery,更新layout文件,添加如下脚本

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"
            asp-fallback-src-include="/lib/jquery/**/*.min.js"
            asp-fallback-src-exclude="**.slim.**"
            asp-fallback-test="window.jQuery">
</script>

src指定从哪里加载jQuery,在CDN加载失败的情况下,asp-fallback-src-include和asp-fallback-src-exclude 使用本地备用的JQuery以及排除本地jQuery文件,asp-fallback-test帮助标签定义JavaScript代码(‘window.jQuery’) ,用来测试是否jQuery从CDN加载成功

如果代码执行失败,那么我们可以确信CDN已经无法使用,因此asp-fallback-src-include和asp-fallbback-src-exclude将会从网站服务器加载

9 CSS帮助标签

CSS帮助标签是用来管理包含和排除CSS文件从视图,下面显示了各种特性:

名字

描述

asp-href-include

指定视图中包含的CSS文件

asp-href-exclude

指定视图中排除的CSS文件

asp-append-version

指定css文件查询的版本号,用作Cache Busting

asp-fallback-href-include

指定包含的CSS文件,在CDN出现问题时

asp-fallback-href-exclude

指定排除的CSS文件,在CDN出现问题时

asp-fallback-href-test-class

指定一个CSS文件类测试CDN是否可用

asp-fallback-href-test-property

使用CSS类的属性测试CDN

asp-fallback-href-test-value

指定一个测试值,用来确定CDN是否可用

9.1 asp-href-include例子

Bootstrap文件位于wwwroot/lib/bootstrap/dist/css目录,如下图所示:

e9c613d0ad01c1069f692af6d48fad8c.png

在head节点下添加如下特性,包含所有的bootstrap的css文件

<link rel="stylesheet" asp-href-include="/lib/bootstrap/**/*min.css" />

我们针对CSS文件使用 (**和*) 匹配模式

** – 匹配任何数量的字符包含'/'

*  –  匹配任何数量的字符,排除'/'

这将添加文件名称已.css结尾,因此将包含下列文件

e5f9d944305bc7ec2fa7faf5ab2f9059.png

添加了大量的css文件像grid,reboot,rtl ,我们可以使用asp-href-exclude来移除它

9.2 asp-href-exclude例子

asp-href-exclude属性用来从视图中排除CSS文件,现在使用它来移除reboot和grid CSS文件. 如下代码所示:

84002dbe066215eddc2f62a3b6adda9a.png

现在,值包含1个CSS文件:

953679fad8eb0bb73a875232c6d38521.png

10 从CDN加载CSS

我们可以从CDN中加载CSS文件,在layout页面添加下面代码:

8bc198988e882957dd9bf1a9e238464a.png

href属性指定CDN的地址,asp-fallback-href-include 和 asp-fallback-href-exclude 表示如果CDN不可用,选择本地站点加载CSS文件

下面3个帮助标签使用测试是否bootstrap文件能够从CDN下载成功:

1. asp-fallback-test-class

2. asp-fallback-test-property

3. asp-fallback-test-value

工作方式是将一个元素添加到的文档中, 这个元素在标记asp-fallback-test-class中定义

如下图所示

6fe42c3fc8058d6f1c528879de54a69b.png

asp-fallback-test-property指定CSS属性,asp-fallback-test-value设置属性的值,这些属性用来判断CDN是否正确加载,如果失败fallback的文件将被加载

源代码地址

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.TagHelpers/AspNetCore.BuiltInTagHelpers

参考文献

[1]https://www.yogihosting.com/aspnet-core-introduction-tag-helpers/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值