Click here to Skip to main content
15,894,343 members
Articles / Web Development / ASP.NET / ASP.NET Core

ASP.NET Core 2.0 Tag Helper Component

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
2 Sep 2017CPOL2 min read 6K   3  
How to dynamically write HTML using Tag Helper Components in ASP.NET Core 2.0. Continue reading...

Problem

How to dynamically write HTML using Tag Helper Components in ASP.NET Core 2.0.

Solution

Create an empty project and add a controller:

HTML
public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }

Add a view:

HTML
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ASP.NET Core 2.0 TagHelperComponent</title>
</head>
<body>
</body>
</html>

Add a Tag Helper Component:

C#
public class MetaTagHelperComponent : TagHelperComponent
    {
        public override int Order => 1;

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "head", 
                         StringComparison.OrdinalIgnoreCase))
            {
                output.PostContent.AppendHtml(
                    $"<meta name=\"description\" content=\"This is a post on 
                          TagHelperComponent\" /> \r\n");
                output.PostContent.AppendHtml(
                    $"<meta name=\"keywords\" content=\"asp.net core, mvc, tag 
                          helpers\" /> \r\n");
            }
        }
    }

Update the Startup class, inject the component class to service container:

C#
public void ConfigureServices(
            IServiceCollection services)
        {
            services.AddSingleton<ITagHelperComponent, MetaTagHelperComponent>();

            services.AddMvc();
        }

        public void Configure(
            IApplicationBuilder app, 
            IHostingEnvironment env)
        {
            app.UseMvcWithDefaultRoute();
        }

Run and observe the page generated (view source or developer tools in browser):

Image 1

Note that the two meta tags were dynamically generated by the Tag Helper Component.

Discussion

ASP.NET Core 2.0 has introduced “Tag Helper Components” that improve and complement Tag Helpers by giving developers the capability to use Dependency Injection with them.

The way this works is that:

  1. We create a Tag Helper to target existing or new (i.e. custom) HTML elements.
  2. We then create a class that inherits from TagHelperComponent and override its Process() method to append HTML content to the Tag Helper’s HTML element.
  3. We then inject this class into the service container, which is executed at runtime.

In case you’re wondering if the solution above is missing a Tag Helper for head HTML element, it’s not. ASP.NET Core team has provided us with two built-in Tag Helpers, one targets head and the other targets the body element: HeadTagHelper and BodyTagHelper

In the solution above, our Tag Helper Component is adding few meta tags to the head element. This could be used, for instance, by a blogging engine to output them for search engine optimization.

I’ve hard-coded entries but of course, using Dependency Injection, we can inject a service that could retrieve these from a database:

C#
public class MetaTagHelperComponent : TagHelperComponent
    {
        private readonly IMetaService service;

        public MetaTagHelperComponent(IMetaService service)
        {
            this.service = service;
        }

        public override int Order => 1;

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "head", 
                         StringComparison.OrdinalIgnoreCase))
            {
                foreach (var item in this.service.GetMetadata())
                    output.PostContent.AppendHtml(
                        $"<meta name=\"{item.Key}\" content=\"{item.Value}\" /> \r\n");
            }
        }
    }

Another possible use-case for a Tag Helper Component, that targets head or body, is to dynamically inject scripts/styles, e.g.:

HTML
public class ScriptsTagHelperComponent : TagHelperComponent
    {
        public override int Order => 99;

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "body", 
                        StringComparison.OrdinalIgnoreCase))
            {
                output.PostContent.AppendHtml(
                        $"<script src='js/jquery.min.js'></script> \r\n");
                output.PostContent.AppendHtml(
                        $"<script src='js/site.js'></script> \r\n");
            }
        }
    }

There is an interesting application of this for JavaScript logging here by Hisham.

Custom Tag Helpers & Components

We can use these components for custom Tag Helpers too. Let’s say we want to target all the footer elements and inject current time (or visitors count, logo, copyright, etc.). We can first create a Tag Helper to target a footer element:

HTML
[HtmlTargetElement("footer")]
    public class FooterTagHelper : TagHelperComponentTagHelper
    {
        public FooterTagHelper(
            ITagHelperComponentManager manager,
            ILoggerFactory logger) : base(manager, logger) { }
    }

Note: The base class is the new TagHelperComponentTagHelper and not the TagHelper used for non-component scenarios.

Now we can create a Tag Helper Component that targets this Tag Helper:

HTML
public class FooterTagHelperComponent : TagHelperComponent
    {
        public override int Order => 1;
        
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "footer", 
                         StringComparison.OrdinalIgnoreCase))
            {
                output.PostContent.AppendHtml(
                    string.Format($"<p><em>{DateTime.Now.ToString()}</em></p>"));
            }
        }
    }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
-- There are no messages in this forum --