Create Custom Tag Helpers in ASP.NET Core

As an ASP.NET programmer we are already familiar with server controls and HTML helpers. What does they do? In simple words they execute some server side logic and generate HTML markup. The HTML markup hence generated is then rendered in the browser. In ASP.NET core you can continue using HTML helpers as in ASP.NET MVC. But, there is a better alternative i.e. the Tag Helpers.

ASP.NET Core tag helpers consist of markup they you place in your views. This markup is special in that it is processed on the server side and renders certain HTML markup. In order to get an idea consider the following Form tag helper:

<form asp-action=”ProcessForm” asp-controller=”Home” method=”post”>

….

….

</form>

The above mark-up indicates that you are using a form tag helper. Notice that the form tag helper has two attributes of the form asp. These attributes mention the action name and the controller name respectively. There is also a method attribute. The asp-action and asp-controller attributes are processed on the server while the method attribute is the standard HTML attribute. The above server side markup gets transformed to this :

<form action=”/home/ProcessForm” method=”post>

….

….

</form>

Tag helpers are better than HTML helpers because they are mark-up friendly. They appear more natural to go along standard HTML markup. What’s more that you can easily build your own custom tag helpers. The article will illustrate how.

The Latestblogposts tag helper – markup

A custom tag helper has two parts: a piece of mark-up that you put in a razor view and a class that houses the processing logic of the tag helper under consideration. Let’s understand with an example. Suppose you are building a blog engine and wish to display a list of latest blog posts belonging to a particular category. You also want to control the number of items being displayed. Considering these requirements let’s say we wish to have this kind of custom tag helper markup in our view:

<latestblogposts Category=”AspNetCore” Count=”10″>

</latestblogposts>

Here, the latestblogpost tag helper puts itself as an independent mark-up element. It has two attributes namely Category and Count. The Category attribute indicates the blog post category or tag to be used (AspNetCore in this case) to pick the latest posts. The Count attribute mentions that 10 items are to be displayed in the latest posts list.

The Latestblogpost tag helper – class

This is the first part of our custom tag helper. Now the remaining part a class named LatestblogpostsTagHelper must be created. This class is shown below:

public class LatestblogpostsTagHelper:TagHelper

{

public string Category { get; set; }

public int Count { get; set; }

public override void Process(TagHelperContext context,

TagHelperOutput output)

{

output.TagName = “div”;

output.Attributes.Add(“class”, “latestBlogPosts”);

using (BlogDbContext db = new BlogDbContext())

{

var query = (from p in db.BlogPosts

where p.Category == Category

orderby p.PublishDate descending

select p

).Take(Count);

StringBuilder sb = new StringBuilder();

foreach(var item in query)

{

sb.AppendFormat(“<h2><a href=’/home/

displaypost/{0}’>{1}</a></h2>”,item.BlogPostID,

item.Title);

}

output.Content.SetHtmlContent(sb.ToString());

}

}

}

Take note of the above code carefully. The LatestblogpostsTagHelper class comes from TagHelper class (Microsoft.AspNetCore.Razor.TagHelpers namespace). The LatestblogpostsTagHelper class has two properties – Category and Count – and an overridden Process() method.

The Category and Count properties belong to the respective attributes used in the tag helper markup. In the Process() method the processing logic of the custom tag helper stays. The Process() method receives TagHelperOutput parameter that is used to render the desired output. The TagName property indicates the HTML tag name of the resultant mark-up (div in this case). The feature collection is made use to set the class feature of the <div> to latestBlogPosts. Then an Entity Framework Core code connects with the data-base and brings records from the BlogPosts table. The BlogDbContext and BlogPost are discussed later.

Notice how the LINQ to Entities query use the Category and Count properties while getting the records. A for each loop then iterates through the latest blog posts and generates a list of hyperlinks for each post. This is done with the help of a StringBuilder. Lastly, SetHtmlContent() method is used to render the HTML fragment.

DbContext and entity class

This completes the Latestblogposts tag helper. Before running the application you must need to add the DbContext and the BlogPost entity class. They are shown below:

[Table(“BlogPosts”)]

public class BlogPost

{

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int BlogPostID { get; set; }

[Required]

[StringLength(200)]

public string Title { get; set; }

[Required]

public string Content { get; set; }

[Required]

[StringLength(50)]

public string Category { get; set; }

[Required]

public DateTime PublishDate { get; set; }

}

public class BlogDbContext:DbContext

{

public DbSet<BlogPost> BlogPosts { get; set; }

protected override void OnConfiguring

(DbContextOptionsBuilder optionsBuilder)

{

optionsBuilder.UseSqlServer(@”data source=.;

initial catalog =BlogDb;

Integrated Security=True;

MultipleActiveResultSets = true”);

}

}

To design a database based on the above DbContext you can use the following commands:

> dotnet ef migrations add MyMigrations

> dotnet ef database update

Of course, you can also designthe database manually and not use these commands.

Using the custom tag helper

In order to use the latestblogposts tag helper successfully on a razor view, it must be made available to the view. You do this using the @addtagHelper directive. You can place this directive either inside the view file itself or better yet inside _ViewImports.cshtml file.

@addTagHelper *,MyWebApplication

The @addTagHelper directive specifies that all the tag helpers (*) from the MyWebApplication assembly (the current web application’s project) are to be made available to the view. You will also get IntelliSense for the custom tag helpers:

After creating the database and adding a few dummy records run the application. The following figure shows a sample run of the application.

If you see the HTML source of the page, you will see this HTML fragment:

<div class=”latestBlogPosts”>

<h2>

<a href=’/home/displaypost/4′>Blog Post Title 2</a>

</h2>

<h2>

<a href=’/home/displaypost/1′>Blog Post Title 1</a>

</h2>

</div>

Tag helpers and Pascal casing

In the above example the tag helper element was <latestblogposts>. What if you wish to use the following tag name?

<Latest-Blog-Posts Category=”AspNetCore” Count=”10″>

</Latest-Blog-Posts>

Here the tag name includes hyphened character. You can’t use hyphen in C# class names. The remedy is to do Pascal casing for the tag helper class name. So, the class name needs to be :

public class LatestBlogPostsTagHelper : TagHelper

{

….

}

The same rule applies for attribute names also. Thus article-category feature would be drawn with ArticleCategory attribute and article-count attribute will communicate to ArticleCount attribute.

Specifying element and attribute mapping manually

In the above example the markup element <latestblogposts> was compared to LatestblogpostsTagHelper class automatically. On the same lines Category and Count attributes were mapped to Category and Count properties automatically. Though this might work well in many situations, at times you might want to specify this mapping. You can do so as mentioned below:

[HtmlTargetElement(“latestblogposts”)]

public class LatestblogpostsTagHelper:TagHelper

{

[HtmlAttributeName(“Category”)]

public string Category { get; set; }

[HtmlAttributeName(“Count”)]

public int Count { get; set; }

….

….

}

As you can see the LatestblogpostsTagHelper class is designed with [HtmlTargetElement] attribute that maps it to the latestblogposts element. Similarly, Category and Count properties are decorated with [HtmlAttributeName] attribute. The [HtmlAttributeName] attribute maps the properties to Category and Count attributes respectively.

Creating tag helpers for standard HTML elements

In the above example we designed a new markup element – <latestblogposts> – to represent a custom tag helper. What if you wish to use a standard HTML element instead of introducing your own? Say for example :

<div article-category=”AspNetCore” article-count=”10″>

</div>

In this case the custom tag helper takes a form of <div> element. The <div> element has two attributes article-category and article-count.

The class that manages the above tag helper is shown below:

[HtmlTargetElement(“div”,Attributes = “article-*”)]

public class LatestBlogPostsTagHelper : TagHelper

{

public string ArticleCategory { get; set; }

public int ArticleCount { get; set; }

public override void Process(

TagHelperContext context,

TagHelperOutput output)

{

output.Attributes.Add(“class”, “latestBlogPosts”);

using (BlogDbContext db = new BlogDbContext())

{

var query = (from p in db.BlogPosts

where p.Category == ArticleCategory

orderby p.PublishDate descending

select p

).Take(ArticleCount);

StringBuilder sb = new StringBuilder();

foreach (var item in query)

{

sb.AppendFormat(“<h2><a href=’/home/

displaypost/{0}’>{1}</a></h2>”,

item.BlogPostID, item.Title);

}

output.Content.SetHtmlContent(sb.ToString());

}

}

}

Notice that the LatestBlogPostsTagHelper class is now decorated with [HtmlTargetElement] attribute. The target element is set to div. Now, there might be several <div> elements on the page. We wish to tell our helper only for a <div> that has article-category and article-count attributes (you could have used any other attribute names). The second parameter sets the Attributes filter to article. This way only the <div> elements having features of the form article are processed by this helper.

We conclude now….. Enjoy coding!

Let us know your opinion in the comments sections below. And feel free to refer Microsoft’s site to gather more information.

If you want to improve your skill in ASP.Net and excel yourself in ASP.NET training program; our institute, CRB Tech Solutions would be of great help and for you. Come and join us with our well structured program for ASP .Net.

Stay connected to CRB Tech for more technical optimization and other updates and information

Don't be shellfish...Buffer this pageEmail this to someoneDigg thisShare on FacebookShare on Google+Share on LinkedInPrint this pageShare on RedditPin on PinterestShare on StumbleUponTweet about this on TwitterShare on Tumblr

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>