ASP.NET Core 2.0 MVC Custom Tag Helpers

Problem

How to create custom Tag Helpers in ASP.NET Core MVC.

Solution

In an empty project, add NuGet packages, then update Startup class to add services and middleware for MVC.

Add a Controller with an action method.

An Employees.cshtml page.

Add a class EmployeeTagHelper.cs.

Discussion

As discussed in the previous post, Tag Helpers help generate HTML by attaching attributes to existing HTML elements or by creating new elements. In this post, we’ve created a new tag to display employee information.

Tag Helper Class

To create custom Tag Helpers, you create a C# class that inherits from TagHelper abstract base class. There are two attributes that help define the behavior of our class:

[RestrictChildren] restricts the nesting structure of tag helpers. For instance, here the employee tag can only have friend tag nested in it.

Note

This also restricts the use of Razor syntax, which I feel is a bit too restrictive!

[HtmlTargetElement] – tag helper names by default are kebab casings of C# class name. However, using this attribute, you can explicitly define tag helper name, its parent tag name, tag structure (self-closing, without end tag) and allowed attributes. You can apply this attribute more than once if the C# class is targeting more than one tag helper.

Linking HTML Elements to C# Properties

Properties in your custom C# class maps to HTML element attributes. You could override this behavior (i.e. stop binding properties to HTML attributes) by using [HtmlAttributeNotBound] attribute on the property. You could also explicitly specify the name of HTML attributes by annotating properties with [HtmlAttributeName].

Process and ProcessAsync (Execution)

Overriding one of these methods enables us to output HTML for our Tag Helpers. There are two parameters to these methods: 

  • TagHelperContext 
    contains a read-only collection of all HTML attributes applied to your tag helper. Also, it contains Items dictionary that can be used to pass the data between nested tag helpers.

  • TagHelperOutput 
    used to set HTML elements and their attributes for the tag helper. There are five properties to set content (PreElement, PreContenet, Content, PostContent, PostElement) and Attributes property to add attributes to tag helper’s HTML. There are also properties to set HTML element that tags helper outputs (TagName) and its closing tag behavior (TagMode).
Model Data

We can populate tag helper properties via model binding by creating properties of type ModelExpression.

Then, using @model directive to declare and use model binding,

Value of the property can be retrieved using Model property of ModelExpression,

ViewContext

Within the tag helper class, we can use ViewContext type to access view’s contextual information e.g. HttpContextModelState etc. This is achieved by declaring a property of type ViewContext and annotating with a [ViewContext] and [HttpAttirubteNotBound] attributes,

Dependency Injection

Tag Helpers can benefit from dependency injection like other parts of ASP.NET Core. Simply add your service in ConfigureServices method of Startup and inject in tag helper using a constructor. The attached sample code demonstrates this.

Tag Builder

Instead of concatenating strings to create HTML output, you could use TagBuilder class. It helps in building HTML element and their attributes. You could create nested tags easily using this mechanism, 

  1. var year = new TagBuilder("span");  
  2.    year.Attributes.Add("class""movie-year");  
  3.    year.InnerHtml.AppendHtml(  
  4.        string.Format("({0})"this.ReleaseYear.Model));  
  5.   
  6.    var title = new TagBuilder("div");  
  7.    title.Attributes.Add("class""movie-title");  
  8.    title.InnerHtml.AppendHtml(  
  9.        string.Format("{0}"this.Title.Model));  
  10.    title.InnerHtml.AppendHtml(year);  
Source Code

GitHub