當咱們新建了一個.Net Core類型的Project時,咱們會看到頁面上有相似於這樣的代碼:html
當咱們運行項目,查看源代碼會發現,瀏覽器中的就是Html代:web
那麼,爲何咱們在頁面寫的代碼會轉化爲html標籤呢?接下來咱們就來探索這個祕密。瀏覽器
當咱們在vs中把鼠標放到這樣的元素上時發現這樣的元素都是一個Microsoft.AspNetCore.Mvc.TagHelpers命名空間下的對象,咱們經過Reflector查看a標籤的對象AnchorTagHelperide
[HtmlTargetElement("a", Attributes="asp-action"), HtmlTargetElement("a", Attributes="asp-controller"), HtmlTargetElement("a", Attributes="asp-area"), HtmlTargetElement("a", Attributes="asp-fragment"), HtmlTargetElement("a", Attributes="asp-host"), HtmlTargetElement("a", Attributes="asp-protocol"), HtmlTargetElement("a", Attributes="asp-route"), HtmlTargetElement("a", Attributes="asp-all-route-data"), HtmlTargetElement("a", Attributes="asp-route-*")] public class AnchorTagHelper : TagHelper { // Fields private IDictionary<string, string> _routeValues; private const string ActionAttributeName = "asp-action"; private const string AreaAttributeName = "asp-area"; private const string ControllerAttributeName = "asp-controller"; private const string FragmentAttributeName = "asp-fragment"; private const string HostAttributeName = "asp-host"; private const string Href = "href"; private const string ProtocolAttributeName = "asp-protocol"; private const string RouteAttributeName = "asp-route"; private const string RouteValuesDictionaryName = "asp-all-route-data"; private const string RouteValuesPrefix = "asp-route-"; // Methods public AnchorTagHelper(IHtmlGenerator generator); public override void Process(TagHelperContext context, TagHelperOutput output); // Properties [HtmlAttributeName("asp-action")] public string Action { get; set; } [HtmlAttributeName("asp-area")] public string Area { get; set; } [HtmlAttributeName("asp-controller")] public string Controller { get; set; } [HtmlAttributeName("asp-fragment")] public string Fragment { get; set; } protected IHtmlGenerator Generator { [CompilerGenerated] get; } [HtmlAttributeName("asp-host")] public string Host { get; set; } public override int Order { get; } [HtmlAttributeName("asp-protocol")] public string Protocol { get; set; } [HtmlAttributeName("asp-route")] public string Route { get; set; } [HtmlAttributeName("asp-all-route-data", DictionaryAttributePrefix="asp-route-")] public IDictionary<string, string> RouteValues { get; set; } [HtmlAttributeNotBound, ViewContext] public ViewContext ViewContext { get; set; } }
首先,這個類繼承自抽象類TagHelper
public abstract class TagHelper : ITagHelper { // Methods protected TagHelper(); public virtual void Init(TagHelperContext context); public virtual void Process(TagHelperContext context, TagHelperOutput output); public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output); // Properties public virtual int Order { [CompilerGenerated] get; } }
TagHelper又繼承自ITagHelper接口
public interface ITagHelper { // Methods void Init(TagHelperContext context); Task ProcessAsync(TagHelperContext context, TagHelperOutput output); // Properties int Order { get; } }
這個接口只有兩個方法,Init和ProcessAsync,咱們也許會猜到,轉化的過程就是經過這兩個方法來轉化的。沒錯,你猜對了。
咱們回到AnchorTagHelper類中,查看Process方法:
public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException("context"); } if (output == null) { throw new ArgumentNullException("output"); } if (output.Attributes.ContainsName("href")) { if ((((this.Action != null) || (this.Controller != null)) || ((this.Area != null) || (this.Route != null))) || (((this.Protocol != null) || (this.Host != null)) || ((this.Fragment != null) || (this.RouteValues.Count != 0)))) { throw new InvalidOperationException(Resources.FormatAnchorTagHelper_CannotOverrideHref("<a>", "asp-action", "asp-controller", "asp-area", "asp-route", "asp-protocol", "asp-host", "asp-fragment", "asp-route-", "href")); } } else { TagBuilder builder; IDictionary<string, object> routeValues = null; if ((this._routeValues != null) && (this._routeValues.Count > 0)) { routeValues = new Dictionary<string, object>(this._routeValues.Count, StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, string> pair in this._routeValues) { routeValues.Add(pair.Key, pair.Value); } } if (this.Area != null) { if (routeValues == null) { routeValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); } routeValues["area"] = this.Area; } if (this.Route == null) { builder = this.Generator.GenerateActionLink(this.ViewContext, string.Empty, this.Action, this.Controller, this.Protocol, this.Host, this.Fragment, routeValues, null); } else { if ((this.Action != null) || (this.Controller != null)) { throw new InvalidOperationException(Resources.FormatAnchorTagHelper_CannotDetermineHrefRouteActionOrControllerSpecified("<a>", "asp-route", "asp-action", "asp-controller", "href")); } builder = this.Generator.GenerateRouteLink(this.ViewContext, string.Empty, this.Route, this.Protocol, this.Host, this.Fragment, routeValues, null); } if (builder != null) { output.MergeAttributes(builder); } } }
,發現這個方法主要就是根據咱們填寫的屬性、ViewContext(View上下文)、routeValue(路由信息)來生成Html標籤,主要方法就是在GenerateRouteLink生成一個TagBuilder類型的對象,再經過output.MergeAttributes(builder);生成TagHelperOutput類型的對象。
那麼,咱們在頁面上寫的屬性是怎麼與AnchorTagHelper中的屬性關聯的呢?
咱們能夠看這個類中的屬性,每一個屬性前面都有一個[HtmlAttributeName("asp-action")] ,標記這個屬性和咱們頁面上寫的asp-**屬性關聯的。
綜上,若是咱們不清楚具體的某個TagHelper有哪些屬性,咱們能夠經過反編譯查看,固然不必。咱們只要經過VS直接經過智能感知系統就能夠點出來這些屬性。
咱們還能夠自定義本身的Tag,只要繼承自ITagHelper,實現方法就能夠
public class WebsiteInformationTagHelper : TagHelper { public WebsiteContext Info { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "section"; output.PostContent.SetContent(string.Format( "<p><strong>Version:</strong> {0}</p>" + Environment.NewLine + "<p><strong>Copyright Year:</strong> {1}</p>" + Environment.NewLine + "<p><strong>Approved:</strong> {2}</p>" + Environment.NewLine + "<p><strong>Number of tags to show:</strong> {3}</p>" + Environment.NewLine, Info.Version.ToString(), Info.CopyrightYear.ToString(), Info.Approved.ToString(), Info.TagsToShow.ToString())); output.SelfClosing = false; } }
<website-information info="new WebsiteContext { Version = new Version(1, 1), CopyrightYear = 1990, Approved = true, TagsToShow = 30 }"/>