《 Pro ASP.NET Core 6 》--- 读书随记(8)
作者:互联网
Part 3
CHAPTER 25
内容来自书籍:
Pro ASP.NET Core 6
Develop Cloud-Ready Web Applications Using MVC, Blazor, and Razor Pages (Ninth Edition)Author: Adam Freeman
需要该电子书的小伙伴,可以留下邮箱,有空看到就会发送的
Using Tag Helpers
Tag helpers 是在视图或页面中转换 HTML 元素的 C # 类。Tag helpers 的常见用途包括使用应用程序的路由配置为表单生成 URL,确保特定类型的元素样式一致,以及用常用的内容片段替换自定义简写元素。
Creating a Tag Helper
我通过创建和应用一个 Tag Helper 来设置 tr 元素的 Bootstrap CSS 类
<tr tr-color="primary">
<th colspan="2">Product Summary</th>
</tr>
转换为:
<tr class="bg-primary text-white text-center">
<th colspan="2">Product Summary</th>
</tr>
Defining the Tag Helper Class
Tag helpers 可以在项目的任何地方定义,但是将它们放在一起会有所帮助,因为它们需要注册才能使用
namespace WebApp.TagHelpers {
public class TrTagHelper: TagHelper {
public string BgColor { get; set; } = "dark";
public string TextColor { get; set; } = "white";
public override void Process(TagHelperContext context,
TagHelperOutput output) {
output.Attributes.SetAttribute("class",
$"bg-{BgColor} text-center text-{TextColor}");
}
}
}
Receiving Context Data
Tag helpers 通过 TagHelperContext 类的实例接收有关它们正在转换的元素的信息
虽然您可以通过 AllAttributesdictionary 访问元素属性的详细信息,但是更方便的方法是定义一个名称与您感兴趣的属性相对应的属性
属性的名称会自动从默认的 HTML 样式 bg-color 转换为 C # 样式 BgColor。您可以使用任何属性前缀,除了 asp- (Microsoft 使用的)和 data-(为发送到客户端的自定义属性保留的)。示例 Tag Helper 将使用 bg-color 和 text-color 属性进行配置,这些属性将为 BgColor 和 textColor 属性提供值,并用于在 Process 方法中配置 tr 元素,如下所示:
Producing Output
Process 方法通过配置作为参数接收的 TagHelperOutput 对象来转换元素。TagHelperOut 对象首先描述出现在视图中的 HTML 元素,然后通过下图描述的属性和方法进行修改。
Registering Tag Helpers
Tag Helper 类在使用之前必须使用@addTagHelper 指令进行注册
如果想要在所有的地方都可以使用Tag Hepler,可以在_ViewImports.cshtml 全局导入
@addTagHelper *, WebApp
第一个参数的含义是指定tag Helper 的类名并且支持通配符,第二部分是指定这个类是在哪个程序集(assembly)定义的
Using a Tag Helper
<tr bg-color="info" text-color="white">
清单25-7中应用属性的 tr 元素已经被转换,但这不是图中显示的唯一更改。默认情况下,Tag helpers 应用于特定类型的所有元素,这意味着视图中的所有 tr 元素已经使用在 Tag Helper 类中定义的默认值进行了转换,因为没有定义任何属性。(有些表行不显示文本的原因是 Bootstrap table-striped类,它将不同的样式应用于替换行。)
事实上,问题更为严重,因为视图导入文件中的@addTagHelper 指令意味着示例 Tag Helper 应用于控制器和 Razor 页面呈现的任何视图中使用的所有 tr 元素。
Narrowing the Scope of a Tag Helper
可以使用 HtmlTargetElement 元素控制由 Tag Helper 转换的元素范围
namespace WebApp.TagHelpers {
[HtmlTargetElement("tr", Attributes = "bg-color,text-color", ParentTag = "thead")]
public class TrTagHelper : TagHelper {
public string BgColor { get; set; } = "dark";
public string TextColor { get; set; } = "white";
public override void Process(TagHelperContext context,
TagHelperOutput output) {
output.Attributes.SetAttribute("class",
$"bg-{BgColor} text-center text-{TextColor}");
}
}
}
Attritribute 属性支持 CSS 属性选择器语法,所以[ bg-color ]匹配具有 bg-color 属性的元素,[ bg-color = primary ]匹配具有 bg-color 属性的元素,该属性的值是primary,并且[ bg-color^=p ]匹配具有 bg-color 属性的元素,该属性的值以 p 开头。上文中 Tag Helper 的属性与 tr 元素匹配,它们同时具有 bg-color 和 text-color 属性,这两个属性都是 head 元素的子元素。
Widening the Scope of a Tag Helper
HtmlTargetElement 属性还可以用来扩展 Tag Helper 的范围,使其匹配范围更广的元素。这是通过将属性的第一个参数设置为星号(* 字符)来完成的,该星号匹配任何元素
[HtmlTargetElement("*", Attributes = "bg-color,text-color")]
如果担心匹配的范围过大,这个属性可以叠加使用
[HtmlTargetElement("tr", Attributes = "bg-color,text-color")]
[HtmlTargetElement("td", Attributes = "bg-color")]
如果想对同一个元素应用不同的tag,可以设置tag之间的顺序,Order属性是继承自TagHelper,用来决定tag的执行顺序
Advanced Tag Helper Features
Creating Shorthand Elements
Tag helpers 并不局限于转换标准的 HTML 元素,亦可以用常用的内容取代自订元素。这对于使视图更加简洁和使其意图更加明显是一个有用的特性
<tablehead bg-color="dark">Product Summary</tablehead>
这个自定义标签是不会被浏览器识别的,所以我们会创建一个Tag Helper来生成具体的标准的HTML元素
namespace WebApp.TagHelpers {
[HtmlTargetElement("tablehead")]
public class TableHeadTagHelper: TagHelper {
public string BgColor { get; set; } = "light";
public override async Task ProcessAsync(TagHelperContext context,
TagHelperOutput output) {
output.TagName = "thead";
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.SetAttribute("class",
$"bg-{BgColor} text-white text-center");
string content = (await output.GetChildContentAsync()).GetContent();
output.Content
.SetHtmlContent($"<tr><th colspan=\"2\">{content}</th></tr>");
}
}
}
然后上面的标签会变成:
<thead class="bg-dark text-white text-center">
<tr>
<th colspan="2">Product Summary</th>
</tr>
</thead>
Creating Elements Programmatically
我们使用标准的c#中的string格式来创建我们需要的内容,但是这不安全,因为很可能会打错字。
一个更安全有效的方法是使用 TagBuilder 类,允许以更结构化的方式创建元素
TagBuilder header = new TagBuilder("th");
header.Attributes["colspan"] = "2";
header.InnerHtml.Append(content);
TagBuilder row = new TagBuilder("tr");
row.InnerHtml.AppendHtml(header);
output.Content.SetHtmlContent(row);
Prepending and Appending Content and Elements
TagHelperOutput 类提供了四个属性,可以很容易地将新内容注入到视图中,使其包围元素或元素的内容
Inserting Content Around the Output Element
namespace WebApp.TagHelpers {
[HtmlTargetElement("*", Attributes = "[wrap=true]")]
public class ContentWrapperTagHelper: TagHelper {
public override void Process(TagHelperContext context,
TagHelperOutput output) {
TagBuilder elem = new TagBuilder("div");
elem.Attributes["class"] = "bg-primary text-white p-2 m-2";
elem.InnerHtml.AppendHtml("Wrapper");
output.PreElement.AppendHtml(elem);
output.PostElement.AppendHtml(elem);
}
}
}
使用<div class="m-2" wrap="true">Inner Content</div>
效果:
Inserting Content Inside the Output Element
namespace WebApp.TagHelpers {
[HtmlTargetElement("*", Attributes = "[highlight=true]")]
public class HighlightTagHelper: TagHelper {
public override void Process(TagHelperContext context,
TagHelperOutput output) {
output.PreContent.SetHtmlContent("<b><i>");
output.PostContent.SetHtmlContent("</i></b>");
}
}
}
使用<tr><th>Name</th><td highlight="true">@Model?.Name</td></tr>
Getting View Context Data
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext Context { get; set; } = new();
ViewContext 属性表示,当创建Tag Helper对象类的新实例时,该属性的值应该被赋予一个 ViewContext,该实例提供正在呈现的视图的详细信息,包括路由数据
如果在 div 元素上定义了匹配的属性,则 HtmlAttributeNotBound 属性阻止将值分配给此属性。这是一个很好的实践,特别是当你正在为其他开发者写 Tag helpers 的时候。
Suppressing the Output Element
Tag helpers 可以通过调用作为 Process 方法参数接收的 TagHelperOutput 对象上的 SuppressOut 方法来防止元素包含在 HTML 响应中
<div show-when-gt="500" for="Price">
<h5 class="bg-danger text-white text-center p-2">
Warning: Expensive Item
</h5>
</div>
namespace WebApp.TagHelpers {
[HtmlTargetElement("div", Attributes = "show-when-gt, for")]
public class SelectiveTagHelper : TagHelper {
public decimal ShowWhenGt { get; set; }
public ModelExpression? For { get; set; }
public override void Process(TagHelperContext context,
TagHelperOutput output) {
if (For?.Model.GetType() == typeof(decimal)
&& (decimal)For.Model <= ShowWhenGt) {
output.SuppressOutput();
}
}
}
}
Tag Helper 使用模型表达式访问属性,并调用 SuppressOutput 方法,除非超过阈值
CHAPTER 26
Using the Built-in Tag Helpers
Enabling the Built-in Tag Helpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Transforming Anchor Elements
A 元素是在应用程序周围导航并向应用程序发送 GET 请求的基本工具。AnchorTagHelper 类用于转换元素的 href 属性,这样它们可以针对使用路由系统生成的 URL,这意味着不需要硬编码的 URL,路由配置的变化将自动反映在应用程序的锚元素中
AnchorTagHelper 简单且可预测,使得在使用应用程序路由配置的元素中生成 URL 变得非常容易。
<td>
<a asp-action="index" asp-controller="home" asp-route-id="@Model?.ProductId"
class="btn btn-sm btn-info text-white">
Select
</a>
</td>
Asp-action 和 asp-controller 属性指定操作方法的名称和定义它的控制器。段变量的值是使用 asp-path-[ name ]属性定义的,例如 asp-path-id 属性为 id 段变量提供一个值,用于为 asp-action 属性选择的 action 方法提供一个参数。
上面最终返回的html是
<a class="btn btn-sm btn-info text-white" href="/Home/index/3">Select</a>
Using Anchor Elements for Razor Pages
Asp-Page 属性用于指定一个 Razor 页面作为锚元素 href 属性的目标。页面的路径以/字符为前缀,@page 指令定义的路由段的值使用 asp-path-[ name ]属性定义。
<a asp-page="/suppliers/list" class="btn btn-secondary">Suppliers</a>
Using the JavaScript and CSS Tag Helpers
ASP.NET Core 提供了一些 Tag helpers,用于通过 script 和 link 元素管理 JavaScript 文件和 CSS 样式表。这些 Tag helpers 强大而灵活,但需要密切关注,以避免产生意想不到的结果。
Managing JavaScript Files
ScriptTagHelper 类是 script 元素的内置 Tag Helper,用于管理/n包含 JavaScript 文件
Selecting JavaScript Files
Asp-src-include 属性用于在使用 globbing 模式的视图中包含 JavaScript 文件。Globbing 模式支持一组用于匹配文件的通配符
Globbing 是确保视图包含应用程序需要的 JavaScript 文件的一种有用方法,即使文件的确切路径发生了变化,这种情况通常发生在文件名中包含版本号或包添加额外文件时。
<script asp-src-include="lib/jquery/**/*.js"></script>
Managing CSS Stylesheets
Selecting Stylesheets
LinkTagHelper 与 ScriptTagHelper 共享许多特性,包括支持 globbing 模式来选择或排除 CSS 文件,这样就不必单独指定它们。能够准确地选择 CSS 文件和 JavaScript 文件一样重要,因为样式表可以有常规和缩小的版本,并且支持源地图
<link asp-href-include="/lib/bootstrap/css/*.min.css"
asp-href-exclude="**/*-reboot*,**/*-grid*,**/*-utilities*, **/*.rtl.*"
rel="stylesheet" />
Using the Data Cache
CacheTagHelper 类允许缓存内容片段,以加速视图或页面的呈现。要缓存的内容使用 cache 元素表示
<h6 class="bg-primary text-white m-2 p-2">
Uncached timestamp: @DateTime.Now.ToLongTimeString()
</h6>
<cache>
<h6 class="bg-primary text-white m-2 p-2">
Cached timestamp: @DateTime.Now.ToLongTimeString()
</h6>
</cache>
CacheTagHelper 类使用的缓存是基于内存的,这意味着它的容量受到可用 RAM 的限制,并且每个应用服务器维护一个单独的缓存。当可用容量不足时,内容将从缓存中弹出,当应用程序停止或重新启动时,整个内容将丢失。
Setting Cache Expiry
<cache expires-after="@TimeSpan.FromSeconds(15)">
Setting a Fixed Expiry Point
<cache expires-on="@DateTime.Parse("2100-01-01")">
我已经指定该数据应该缓存到2100年。这不是一个有用的缓存策略,因为应用程序很可能会在下个世纪开始之前重新启动,但它确实说明了如何在将来指定一个固定点,而不是表示相对于内容被缓存的时刻的到期点。
Setting a Last-Used Expiry Period
<cache expires-sliding="@TimeSpan.FromSeconds(10)">
expires-sliding属性用于指定内容没有从缓存中检索到的过期时间
如果在10秒内重新加载页面,将使用缓存的内容。如果等待重新加载页超过10秒,那么缓存的内容将被丢弃,视图组件将用于生成新内容,进程将重新开始。
Using Cache Variations
<cache expires-sliding="@TimeSpan.FromSeconds(10)" vary-by-route="action">
默认情况下,所有请求都接收相同的缓存内容。CacheTagHelper 类可以维护缓存内容的不同版本,并使用它们来满足不同类型的 HTTP 请求,这些请求是使用名称开头为 vary-by 的属性之一指定的
您将看到,每个窗口都会收到自己的缓存内容和自己的到期日期,因为每个请求都会产生不同的action路由值。
Using the Hosting Environment Tag Helper
Environment TagHelper 类应用于自定义环境元素,并根据宿主环境确定在发送到浏览器的 HTML 中是否包含内容区域
<environment names="development">
<h2 class="bg-info text-white m-2 p-2">This is Development</h2>
</environment>
<environment names="production">
<h2 class="bg-danger text-white m-2 p-2">This is Production</h2>
</environment>
CHAPTER 27
Using the Forms Tag Helpers
这章节描述了用于创建 HTML 表单的内置 Tag helpers。这些 Tag helpers 确保表单提交给正确的操作或页面处理程序方法,并且元素准确地表示特定的模型属性
Understanding the Form Handling Pattern
首先,浏览器发送一个 HTTP GET 请求,这将导致包含表单的 HTML 响应,从而使用户可以向应用程序提供数据。用户单击一个按钮,该按钮通过 HTTP POST 请求提交表单数据,这允许应用程序接收和处理用户的数据。处理完数据后,将发送响应,该响应将浏览器重定向到确认用户操作的 URL。
这就是所谓的 POST/Redirect/Get 模式,重定向非常重要,因为它意味着用户可以单击浏览器的重载按钮而无需发送另一个 POST 请求,这可能会导致无意中重复某个操作。
Creating a Controller to Handle Forms
public async Task<IActionResult> Index(long id = 1) {
return View("Form", await context.Products.FindAsync(id));
}
[HttpPost]
public IActionResult SubmitForm() {
foreach (string key in Request.Form.Keys
.Where(k => !k.StartsWith("_"))) {
TempData[key] = string.Join(", ", Request.Form[key]);
}
return RedirectToAction(nameof(Results));
}
public IActionResult Results() {
return View();
}
Using Tag Helpers to Improve HTML Forms
上一节的例子展示了处理 HTML 表单的基本机制,但是 ASP.NET Core 包含了转换表单元素的 Tag helpers
Working with Form Elements
FormTagHelper 类是表单元素的内置 Tag Helper,用于管理 HTML 表单的配置,以便它们针对正确的操作或页面处理程序,而不需要对 URL 进行硬编码
<form asp-action="submitform" method="post">
<form asp-page="FormHandler" method="post">
Working with input Elements
Input 元素是 HTML 表单的骨干,为用户提供应用程序的主要非结构化数据。InputTagHelper 类用于转换输入元素,以便它们反映用于收集的视图模型属性的数据类型和格式
<input class="form-control" asp-for="Name" />
Applying Formatting via the Model Class
[DisplayFormat(DataFormatString = "{0:c2}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
Working with label Elements
<label asp-for="ProductId"></label>
Working with Select and Option Elements
<select class="form-control" asp-for="CategoryId">
<option value="1">Watersports</option>
<option value="2">Soccer</option>
<option value="3">Chess</option>
</select>
<select class="form-control" asp-for="CategoryId" asp-items="@ViewBag.Categories">
</select>
Working with Text Areas
Textarea 元素用于从用户那里获取大量的文本,通常用于非结构化数据,例如注释或观察。
<textarea class="form-control" asp-for="Supplier.Name"></textarea>
Using the Anti-forgery Feature
结果中显示的 _ RequestVerificationToken 表单值是 FormTagHelper 应用于防止跨站请求伪造的安全特性。跨站请求伪造(CSRF)利用用户请求通常被认证的方式来开发 web 应用程序。大多数 Web 应用程序ーー包括那些使用 ASP.NET Core 创建的应用程序ーー都使用 Cookie 来识别哪些请求与某个特定会话相关联,而用户标识通常与这些请求相关联。
CSRF ーー也称为 XSRF ーー依赖于用户在使用 Web 应用程序后访问恶意网站,而且没有明确结束会话。应用程序仍将用户的会话视为处于活动状态,并且浏览器存储的 Cookie 尚未过期。恶意站点包含 JavaScript 代码,该代码向应用程序发送表单请求,以便在未经用户同意的情况下执行操作ーー操作的确切性质将取决于被攻击的应用程序。由于 JavaScript 代码是由用户的浏览器执行的,因此对应用程序的请求包括会话 cookie,应用程序在用户不知情或未经用户同意的情况下执行操作。
如果表单元素不包含 action 属性ーー因为它是由具有 asp-controller、 asp-action 和 asp-page 属性的路由系统生成的ーー那么 FormTagHelper 类将自动启用反 CSRF 特性,即将安全令牌作为 cookie 添加到响应中。将包含相同安全令牌的隐藏输入元素添加到 HTML 表单中
Enabling the Anti-forgery Feature in a Controller
默认情况下,控制器接受 POST 请求,即使它们不包含所需的安全令牌
[AutoValidateAntiforgeryToken]
public class FormController : Controller
Enabling the Anti-forgery Feature in a Razor Page
防伪功能在 Razor 中默认启用
Using Anti-forgery Tokens with JavaScript Clients
默认情况下,防伪特性依赖于 ASP.NET Core 应用程序能够在 HTML 表单中包含一个元素,当表单提交时,浏览器会发回该元素。这对 JavaScript 客户端不起作用,因为 ASP.NET Core 应用程序提供数据而不是 HTML,所以没有办法插入隐藏元素并在将来的请求中接收它。
对于 Web 服务,防伪令牌可以作为 JavaScript 可读 cookie 发送,JavaScript 客户机代码读取该 cookie 并将其作为 POST 请求中的头文件包含在内
builder.Services.Configure<AntiforgeryOptions>(opts => {
opts.HeaderName = "X-XSRF-TOKEN";
});
var app = builder.Build();
IAntiforgery antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use(async (context, next) => {
if (!context.Request.Path.StartsWithSegments("/api")) {
string? token = antiforgery.GetAndStoreTokens(context).RequestToken;
if (token != null) {
context.Response.Cookies.Append("XSRF-TOKEN",
token,
new CookieOptions { HttpOnly = false });
}
}
await next();
});
需要一个自定义中间件组件来设置 cookie,在这个示例中,cookie 被命名为 XSRF-TOKEN。Cookie 的值是通过 IAntiForgery 服务获得的,必须将 HttpOnly 选项设置为 false,以便浏览器允许 JavaScript 代码读取 Cookie。
标签:Core,ASP,Helper,元素,应用程序,Tag,随记,public,属性 来源: https://www.cnblogs.com/huangwenhao1024/p/16439350.html