日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TagHelper是怎么实现的

發布時間:2023/12/4 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TagHelper是怎么实现的 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

眾所周知,在asp.net core中編寫Razor視圖的時候,用了一種新的寫法--TagHelper

那這個TagHelper是怎么回事呢?

?

首先來看看TagHelper的項目位置,它是位于Microsoft.AspNetCore.Mvc.TagHelpers。

如果看到project.json,可以發現,它還依賴一個比較重要的東西Microsoft.AspNetCore.Mvc.Razor

為什么這么說呢,其實很簡單,看了里面諸多TagHelper,就會發現,里面都是繼承了

Microsoft.AspNetCore.Razor.TagHelpers下面的TagHelper這個抽象類。

下面就以我們天天用到的表單--FormTagHelper為例來說一下,他是怎么實現的。

首先要看看TagHelper這個抽象類:

public abstract class TagHelper : ITagHelper

? ? {

? ? ? ? protected TagHelper(); ? ??

? ? ? ? public virtual int Order { get; }

? ? ? ? public virtual void Init(TagHelperContext context);

? ? ? ? public virtual void Process(TagHelperContext context, TagHelperOutput output);

? ? ? ? public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output);

? ? }

面包含兩比較重要的方法:Process和ProcessAsync

其實看方法名就應該知道一個是同步的方法一個是異步的方法

因為這個是輸出html的方法,你說,這能不重要嗎?下面來看看FormTagHelper的具體實現吧!

[HtmlTargetElement("form", Attributes = ActionAttributeName)]

先來看看HtmlTargetElement這個Attribute是用來干嘛的

簡單來說,它指定了我們html標簽(<form></form>)以及一些相關的元素。

可以看到,諸多Attributes = XXXAttributeName,其中的XXXAttributeName是在類里面定義的變量。

private const string ActionAttributeName = "asp-action";

? ? ? ? private const string AntiforgeryAttributeName = "asp-antiforgery";

? ? ? ? private const string AreaAttributeName = "asp-area";

? ? ? ? private const string ControllerAttributeName = "asp-controller";

? ? ? ? private const string RouteAttributeName = "asp-route";

? ? ? ? private const string RouteValuesDictionaryName = "asp-all-route-data";

? ? ? ? private const string RouteValuesPrefix = "asp-route-";

? ? ? ? private const string HtmlActionAttributeName = "action";

再來看看下面的圖,相對比一看,是不是就很清晰了呢?

我們可以看到下面的好幾個屬性,如Controller,它的上面是有 HtmlAttributeName來標注的

而且這個指向的名字還是ControllerAttributeName(也就是asp-controller)。這個就是用來接收asp-controller的值。

[HtmlAttributeName(ControllerAttributeName)]
public string Controller { get; set; }

相對來說,這樣做只是起了個別名。


[HtmlTargetElement("form", Attributes = ActionAttributeName)]

? ? [HtmlTargetElement("form", Attributes = AntiforgeryAttributeName)]

? ? [HtmlTargetElement("form", Attributes = AreaAttributeName)]

? ? [HtmlTargetElement("form", Attributes = ControllerAttributeName)]

? ? [HtmlTargetElement("form", Attributes = RouteAttributeName)]

? ? [HtmlTargetElement("form", Attributes = RouteValuesDictionaryName)]

? ? [HtmlTargetElement("form", Attributes = RouteValuesPrefix + "*")]

? ? public class FormTagHelper : TagHelper

當然,我們也是可以不指定別名的,也可以不用在HtmlTargetElement指明Attributes

好比如下的代碼,就可以直接用Controller

[HtmlTargetElement("form")]
public class FormTagHelper : TagHelper
{
public string Controller { get; set; }
}


還有一個RouteValues的屬性,它是一個鍵值對,用來存放參數的,具體可以怎么用呢?

總的來說有兩種用法。可以看到它指向asp-all-route-data和asp-route-

1 [HtmlAttributeName(RouteValuesDictionaryName, DictionaryAttributePrefix = RouteValuesPrefix)]

用法如下:一種是用asp-all-route-data來接收一個IDictionary類型的變量,一種是通過asp-route-*的方式來接收參數*的值。

這兩種寫法是等價的。

下面就是FormTagHelper的構造函數和一個Generator屬性

public FormTagHelper(IHtmlGenerator generator)
{
Generator = generator;
?}
protected IHtmlGenerator Generator { get; }

由于在Core中,依賴注入隨處可見,看到這個寫法馬上就是想到了這個

果不其然,發現其對應了一個實現類:DefaultHtmlGenerator。

public class DefaultHtmlGenerator : IHtmlGenerator

? ? { ? ? ??

? ? ? ? public DefaultHtmlGenerator(IAntiforgery antiforgery, IOptions<MvcViewOptions> optionsAccessor, IModelMetadataProvider metadataProvider, IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, ClientValidatorCache clientValidatorCache); ? ?

? ? ? ? public virtual TagBuilder GenerateActionLink(ViewContext viewContext, string linkText, string actionName, string controllerName, string protocol, string hostname, string fragment, object routeValues, object htmlAttributes);

? ? ? ? public virtual IHtmlContent GenerateAntiforgery(ViewContext viewContext); ? ?

? ? ? ? public virtual TagBuilder GenerateForm(ViewContext viewContext, string actionName, string controllerName, object routeValues, string method, object htmlAttributes); ??

? ? ? ? public virtual TagBuilder GenerateLabel(ViewContext viewContext, ModelExplorer modelExplorer, string expression, string labelText, object htmlAttributes); ?

? ? ? ? public virtual TagBuilder GenerateTextArea(ViewContext viewContext, ModelExplorer modelExplorer, string expression, int rows, int columns, object htmlAttributes);

? ? ? ? public virtual TagBuilder GenerateTextBox(ViewContext viewContext, ModelExplorer modelExplorer, string expression, object value, string format, object htmlAttributes); ? ? ??

? ? ? ? protected virtual TagBuilder GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, string expression, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes);

? ? ? ? protected virtual TagBuilder GenerateLink(string linkText, string url, object htmlAttributes);

     ....省略部分

? ? }

這個類里面,我們看到了熟悉的TagBuilder,就算不去看它里面的實現都能知道它是用來干嘛的

它就是用來創建我們的Html標簽,相信用過MVC的,多多少少都擴展過HtmlHelper,這是類似的。

最后,也是最最重要的重寫的Process方法。

可以看到開始就判斷了表單<form>中是否包含了action這個屬性output.Attributes.ContainsName(HtmlActionAttributeName)

如果包含,就是正常的html標簽。換句話說,正常的html寫法和我們的TagHelper方法會有沖突,只能用其中一種。

當我們這樣寫的時候,編譯能通過。

但是,運行的時候就會出錯。

再下面的處理就是用了TagBuilder去處理了。

收集路由的數據放到一個字典中->區域是否存在->用Generator去創建form表單,返回TagBuilder對象->TagHelperOutput對象把tagbuilder的innerhtml等信息輸出。

如下面的寫法:

1 <form method="post" asp-action="Get" asp-controller="Product" asp-antiforgery="false" asp-route-id="2">2 <button type="submit">submit</button>3 </form>

生成對應的html如下:

1 <form method="post" action="/Product/Get/2">2 <button type="submit">submit</button>3 </form>

?

到這里,FormTagHelper的講解就算是OK,至于其他的,原理都是差不多,就不再累贅了。

?

來看看,到底有多少種TagHelper(還沒有部分沒有列出來),以及它們包含的屬性。

?

?

下面是我們自己寫一個TagHelper——CatcherATagHelper,這個TagHelper是干什么的呢?它只是一個精簡版的A標簽。

using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.Rendering;

using Microsoft.AspNetCore.Mvc.Routing;

using Microsoft.AspNetCore.Mvc.TagHelpers;

using Microsoft.AspNetCore.Mvc.ViewFeatures;

using Microsoft.AspNetCore.Razor.TagHelpers;


namespace Catcher.EasyDemo.Controllers.TagHelpers

{

? ? [HtmlTargetElement("catcher-a")]

? ? public class CatcherATagHelper:TagHelper

? ? { ? ? ??

? ? ? ? public CatcherATagHelper(IHtmlGenerator generator, IUrlHelperFactory urlHelperFactory)

? ? ? ? {

? ? ? ? ? ? this.Generator = generator;

? ? ? ? ? ? UrlHelperFactory = urlHelperFactory;

? ? ? ? }


? ? ? ? [HtmlAttributeNotBound]

? ? ? ? public IUrlHelperFactory UrlHelperFactory { get; }


? ? ? ? protected IHtmlGenerator Generator { get; }

? ? ? ??

? ? ? ? public override int Order

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? return -1000;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? ? ? ? ??

? ? ? ? public string Action { get; set; }

? ? ? ??

? ? ? ? public string Controller { get; set; }


? ? ? ? public string LinkText { get; set; }


? ? ? ? [ViewContext]

? ? ? ? [HtmlAttributeNotBound]

? ? ? ? public ViewContext ViewContext { get; set; }


? ? ? ? public override void Process(TagHelperContext context, TagHelperOutput output)

? ? ? ? {

? ? ? ? ? ? //method 1

? ? ? ? ? ? if (Action != null || Controller != null)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? output.Attributes.Clear();


? ? ? ? ? ? ? ? var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);


? ? ? ? ? ? ? ? output.TagName = "a";


? ? ? ? ? ? ? ? output.Attributes.SetAttribute("href", urlHelper.Action(Action, Controller));

? ? ? ? ? ? ? ? //whether the inner html is null

? ? ? ? ? ? ? ? if (output.Content.IsEmptyOrWhiteSpace)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? output.PreContent.SetContent(LinkText);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? //method 2

? ? ? ? ? ? //TagBuilder tagBuilder;

? ? ? ? ? ? //if (Action != null || Controller != null)

? ? ? ? ? ? //{

? ? ? ? ? ? // ? ?tagBuilder = Generator.GenerateActionLink(

? ? ? ? ? ? // ? ? ? ? ? ?ViewContext,

? ? ? ? ? ? // ? ? ? ? ? ?linkText: string.Empty,

? ? ? ? ? ? // ? ? ? ? ? ?actionName: Action,

? ? ? ? ? ? // ? ? ? ? ? ?controllerName: Controller,

? ? ? ? ? ? // ? ? ? ? ? ?protocol: string.Empty,

? ? ? ? ? ? // ? ? ? ? ? ?hostname: string.Empty,

? ? ? ? ? ? // ? ? ? ? ? ?fragment: string.Empty,

? ? ? ? ? ? // ? ? ? ? ? ?routeValues: null,

? ? ? ? ? ? // ? ? ? ? ? ?htmlAttributes: null);


? ? ? ? ? ? // ? ?output.TagName = "a";

? ? ? ? ? ? // ? ?//whether the inner html is null

? ? ? ? ? ? // ? ?if (output.Content.IsEmptyOrWhiteSpace)

? ? ? ? ? ? // ? ?{

? ? ? ? ? ? // ? ? ? ?output.PreContent.SetContent(LinkText);

? ? ? ? ? ? // ? ?}

? ? ? ? ? ? // ? ?output.MergeAttributes(tagBuilder);

? ? ? ? ? ? //}

? ? ? ? }

? ? }

}

這里提供了兩種寫法供大家參考

一種是借助IUrlHelperFactory去生成鏈接

一種是借助IHtmlGenerator去生成鏈接

好了之后要怎么用呢?

不知道大家有沒有留意_ViewImports.cshtml這個文件

1 @using Catcher.EasyDemo.Website2 @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers3 @inject Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration TelemetryConfiguration

這個是默認情況下幫我們添加的TagHelper

我們可以在要用到那個TagHelper的地方添加就好

@{
?Layout = null;
}
@addTagHelper Catcher.EasyDemo.Controllers.TagHelpers.CatcherATagHelper , Catcher.EasyDemo.Controllers
<catcher-a action="list" controller="product" link-text="text">With LinkText And InnerHtml</catcher-a>
<br />
<catcher-a action="list" controller="product" link-text="">Without LinkText</catcher-a>
<br />
<catcher-a action="list" controller="product" link-text="Only With LinkText"></catcher-a>

?

addTagHelper的用法如下:

@addTagHelper 你的TagHelper , 你的TagHelper所在的命名空間

或者更直接

@addTagHelper * , 你的TagHelper所在的命名空間?

可以添加,當然也可以刪除,刪除是@removeTagHelper

當我們在自己的框架中完全重寫了一套自己的TagHelper,那么這個時候,微軟自己的TagHelper我們就可以通過下面的方法來移除了。

@removeTagHelper * , Microsoft.AspNetCore.Mvc.TagHelpers

原文地址:http://www.cnblogs.com/catcher1994/p/5790720.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的TagHelper是怎么实现的的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。