HtmlAttributeName connects a tag helper property to an HTML attribute name or prefix. It lets Razor bind view attributes to deliberately named C# properties instead of relying only on automatic naming. section 8.1.2 section 25.2.1
For prefixed binding, decorate a dictionary-valued property with HtmlAttributeName and give it a prefix such as page-url-. Every element attribute beginning with that prefix is collected into the dictionary. section 8.1.2
The bound values can then participate directly in tag-helper behavior:
- The tag helper passes the collected PageUrlValues dictionary to IUrlHelper.Action when generating href values. section 8.1.2
- A view can preserve the current category with page-url-category="@Model.CurrentCategory!" without adding a separate property for every route value. section 8.1.2
- The resulting pagination URLs retain category filters, so selecting another page does not return products from all categories. section 8.1.2
Custom names for tag-helper properties
Automatic conversion maps an HTML-style attribute such as bg-color to the C# property BgColor. HtmlAttributeName provides an escape hatch when that default name is unclear or undesirable; a tag helper can explicitly choose the HTML attribute represented by a property. Attribute prefixes cannot use asp- or data-. section 25.2.1
Listing 8.4 Prefixed values in the PageLinkTagHelper.cs file in the SportsStore/ Infrastructure folder
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using SportsStore.Models.ViewModels;
namespace SportsStore.Infrastructure {
[HtmlTargetElement("div", Attributes = "page-model")]
public class PageLinkTagHelper : TagHelper {
private IUrlHelperFactory urlHelperFactory;
public PageLinkTagHelper(IUrlHelperFactory helperFactory) {
urlHelperFactory = helperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext? ViewContext { get; set; }
public PagingInfo? PageModel { get; set; }
public string? PageAction { get; set; }
[HtmlAttributeName(DictionaryAttributePrefix = "page-url-")]
public Dictionary<string, object> PageUrlValues { get; set; }
= new Dictionary<string, object>();
public bool PageClassesEnabled { get; set; } = false;
public string PageClass { get; set; } = String.Empty;
public string PageClassNormal { get; set; } = String.Empty;
public string PageClassSelected { get; set; } = String.Empty;
public override void Process(TagHelperContext context,
TagHelperOutput output) {
if (ViewContext != null && PageModel != null) {
IUrlHelper urlHelper
= urlHelperFactory.GetUrlHelper(ViewContext);
TagBuilder result = new TagBuilder("div");
for (int i = 1; i <= PageModel.TotalPages; i++) {
TagBuilder tag = new TagBuilder("a");
PageUrlValues["productPage"] = i;
tag.Attributes["href"] = urlHelper.Action(PageAction,
PageUrlValues);
if (PageClassesEnabled) {
tag.AddCssClass(PageClass);
tag.AddCssClass(i == PageModel.CurrentPage
? PageClassSelected : PageClassNormal);
}
tag.InnerHtml.Append(i.ToString());
result.InnerHtml.AppendHtml(tag);
}
output.Content.AppendHtml(result.InnerHtml);
}
}
}
}
Inspect the complete PageLinkTagHelper implementation to see HtmlAttributeName applied alongside route-value binding and URL generation. section 8.1.2
