Easy Way To Use Tag Helpers in ASP.NET MVC 6
ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that enables a clean separation of concerns and that gives you full control over markup for enjoyable, agile development. ASP.NET MVC includes many features that enable fast, TDD-friendly development for creating sophisticated applications that use the latest web standards.
Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files. For example, the built-in ImageTagHelper can append a version number to the image name. Whenever the image changes, the server generates a new unique version for the image, so clients are guaranteed to get the current image (instead of a stale cached image). There are many built-in Tag Helpers for common tasks – such as creating forms, links, loading assets and more – and even more available in public GitHub repositories and as NuGet packages. Tag Helpers are authored in C#, and they target HTML elements based on element name, attribute name, or parent tag. For example, the built-in LabelTagHelper can target the HTML <label> element when the LabelTagHelper attributes are applied. If you’re familiar with HTML Helpers, Tag Helpers reduce the explicit transitions between HTML and C# in Razor views. Tag Helpers compared to HTML Helpers explains the differences in more detail.
Writing a Custom Tag Helper in ASP.NET MVC 6
Let’s say we want to write a custom tag helper for rendering a <time> tag based on aDateTime. Those <time> tags can be used to represent dates and times in a machine-readable format. However, they require a very specific date format that we shouldn’t have to repeat over and over again. Here’s how we would use our tag helper:
@{
var exampleDate = new DateTime(2016, 12, 02, 14, 50, 31, DateTimeKind.Utc);
}
<time asp-date-time="@exampleDate" />
The output should be something along the lines of the following:
<time datetime="2016-12-02T14:50:31Z" title="Wednesday, December 2, 2016 02:50 PM UTC">December 2, 2016 2:50 PM</time>
We’ll start by creating a custom class that derives from the TagHelper class found in theMicrosoft.AspNet.Razor.TagHelpers namespace. We’ll also create a property to hold the datetime that’s passed in through the asp-date-time attribute:
public class TimeTagHelper : TagHelper
{
[HtmlAttributeName("asp-date-time")]
public DateTime DateTime { get; set; }
}
However, we only want to apply our tag helper to <time> tags that specify the asp-date-time attribute, so we’ll explicitly restrict it to those using the HtmlTargetElement attribute on the tag helper class:
[HtmlTargetElement("time", Attributes = DateTimeAttributeName)]
public class TimeTagHelper : TagHelper
{
private const string DateTimeAttributeName = "asp-date-time";
[HtmlAttributeName(DateTimeAttributeName)]
public DateTime DateTime { get; set; }
}
To specify our tag helper’s behavior, we’ll override the Process method and add our datetime manipulation logic inside of it. We’re setting both a machine-readable datetimeattribute and a human-readable title attribute:
[HtmlTargetElement("time", Attributes = DateTimeAttributeName)]
public class TimeTagHelper : TagHelper
{
private const string DateTimeAttributeName = "asp-date-time";
[HtmlAttributeName(DateTimeAttributeName)]
public DateTime DateTime { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes["datetime"] = DateTime.ToString("yyyy-MM-dd'T'HH:mm:ss") + "Z";
output.Attributes["title"] = DateTime.ToString("dddd, MMMM d, yyyy 'at' h:mm tt");
}
}
Note that we’ll also have to add a line to _ViewImports.cshtml for our tag helper to be recognized within Razor views:
@addTagHelper "*, YourTagHelperAssemblyName"
If we now render a <time> tag using this simple version of the tag helper, we get both attributes, but no inner HMTL (no content). Let’s extend our tag helper such that it adds a default piece of inner HTML if the <time> tag doesn’t define any child content. To do this, we’ll await and inspect the GetChildContentAsync method, which means that we’ll have to override ProcessAsync instead of Process:
[HtmlTargetElement("time", Attributes = DateTimeAttributeName)]
public class TimeTagHelper : TagHelper
{
private const string DateTimeAttributeName = "asp-date-time";
[HtmlAttributeName(DateTimeAttributeName)]
public DateTime DateTime { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.Attributes["datetime"] = DateTime.ToString("yyyy-MM-dd'T'HH:mm:ss") + "Z";
output.Attributes["title"] = DateTime.ToString("dddd, MMMM d, yyyy 'at' h:mm tt");
var childContent = await output.GetChildContentAsync();
if (childContent.IsEmpty)
{
output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetContent(DateTime.ToString("MMMM d, yyyy h:mm tt"));
}
}
}
Now we should get the output we want:
<time datetime="2016-12-02T14:50:31Z" title="Wednesday, December 2, 2016 02:50 PM UTC">December 2, 2016 2:50 PM</time>

