Introduction to Tag Helpers in ASP.NET Core

Introduction to Tag Helpers in ASP.NET Core

Tag Helpers are a new addition in ASP.NET Core MVC, they are used to perform defined transformations on HTML elements. With Tag Helpers you can enable server-side code to participate in creating and rendering the HTML elements in Razor files.

This tutorial is a part of the series called Tag Helpers in ASP.NET Core. It contains 3 tutorials.

Tag Helpers are of 2 types:

  • 1. Built-In Tag Helpers – that comes pre-built in the Core Framework, and perform common tasks like creating forms, showing validation messages, etc.
  • 2. Custom Tag Helper – that can be created by you to perform your desired transformation on an HTML element.

First you will look into Built-In tag helpers then I will explain how to create your own Custom Tag Helper.

Creating an Application to understand Tag Helpers

Start by creating a new ASP.NET Core Web Application in your Visual Studio. Name this application as TagHelpers. Select the Empty Template, framework as .NET Core and version as ASP.NET Core 3.1.

Change the Startup.cs class content as highlighted by the code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace TagHelpers
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
Add Model

Create a Models folder in the root of the application and add class called Products.cs to it. The code of this class is given below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TagHelpers.Models
{
    public class Product
    {
        public string Name { get; set; }
        public float Price { get; set; }
        public int Quantity { get; set; }
    }
}

Now add a new class file called Repository.cs class inside the Models folder with the code given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TagHelpers.Models
{
    public interface IRepository
    {
        IEnumerable<Product> Products { get; }
        void AddProduct(Product newProduct);
    }

    public class ProductRepository : IRepository
    {
        private List<Product> products = new List<Product> {
            new Product { Name = "Men Shoes", Price = 99.99F, Quantity= 100},
            new Product { Name = "Women Shoes", Price = 199.99F, Quantity= 200},
            new Product { Name = "Children Games", Price = 299.99F, Quantity= 300},
            new Product { Name = "Coats", Price = 399.99F, Quantity= 400},
        };

        public IEnumerable<Product> Products => products;
        public void AddProduct(Product newProduct)
        {
            products.Add(newProduct);
        }
    }
}

The repository.cs has an IRepository Interface which contains two members –

  • 1. An IEnumerable property for iterating over all products.
  • 2. A function called AddProduct to add products.

The repository.cs class also has a ProductRepository class that implements the IRepository Interface. The work of the ProductRepository is to provide with a repository (in-memory storage) of product to the application.

  • It stores products in a private list (by name products) and also has a method called AddProduct to add new products to the private list.
  • It also has an IEnumerable property for iterating over the products (by name Products).
Register Repository as a Service

Go to the Startup class and registers the repository as a service using the singleton life cycle. This will help controllers to fetch the products from the repository without creating it’s object. This feature is known as Dependency Injection which I have explain you in details in the Dependency Injection Tutorial.

The changes which you need to make in the Startup class is highlighted in the below code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TagHelpers.Models;

namespace TagHelpers
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IRepository, ProductRepository>();
            services.AddControllersWithViews();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // keep it unchanged
        }
    }
}

Add Controller

Create a Controllers folder in the root of your application and add an Empty Controller to it, name it as HomeController.

Change the HomeController code as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using TagHelpers.Models;

namespace TagHelpers.Controllers
{
    public class HomeController : Controller
    {
        private IRepository repository;
        public HomeController(IRepository repo)
        {
            repository = repo;
        }

        public IActionResult Index()
        {
            return View(repository.Products);
        }
    }
}

Notice the constructor which takes an IRepository object. The dependency injection feature will automatically create the object of the ProductRepository class when the HomeController is initiated.

This is done because I registered the ProductRepository class, as a service using the singleton life cycle, in the ConfigureServices method, there I told ASP.NET Core to automatically provide the object of the ProductRepository class whenever some code calls for creating an object of IRepository interface.

The Index Action simply returns the IEnumerable property that contains all the products in the repository.

Add _ViewStart.cshtml, _ViewImports.cshtml

Create a Views folder in the root of your application for keeping your View files. Inside this folder add the following 2 files:

1. _ViewStart.cshtml

@{
    Layout = "_Layout";
}

2. _ ViewImports.cshtml

@using TagHelpers.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

The @addTagHelper provides Built-In Tag Helpers, defined in an assembly called Microsoft.AspNetCore.Mvc.TagHelpers, available in the application.

I have also imported the TagHelpers.Models namespace so that I don’t have to import it on my views everytime.

Create Layout File

Create a Shared folder inside the Views folder and inside this folder add _ Layout.cshtml file. Change the code of the file with the highlighted code as shown below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" asp-href-include="lib/bootstrap/css/bootstrap.min.css" />
</head>
<body>
    <div class="container-fluid">
        @RenderBody()
    </div>
</body>
</html>

Notice I have added the reference of bootstrap.css file in the head section of the layout. I have also given a bootstrap class to the div like class="container-fluid".

You also need to add the Bootstrap package by Libman inside the wwwroot/lib folder of your project, see How to Install Bootstrap Package in ASP.NET Core Application in Visual Studio
Add View

Create another folder called Home inside the Views folder. Next add Index View to this Home folder with contents as given below:

@model IEnumerable<Product>
 
<table class="table table-sm table-bordered">
    <thead class="bg-dark text-white">
        <tr>
            <th>Name</th>
            <th>Price</th>
            <th>Quantity</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model)
        {
            <tr>
                <td>@product.Name</td>
                <td>@product.Price</td>
                <td>@product.Quantity</td>
            </tr>
        }
    </tbody>
</table>

You may remember that the Index action of the Home controller returns an IEnumerable type that contains all the products in the repository. Therefore in this view I have declared my Model as IEnumerable type. Then I am simply showing all the products in an HTML table.

Notice the code inside the tbody where I am looping through all the products to create a separate tr element for each of them.

The CSS classes used inside the table and thead are Bootstrap classes for giving them text color, border and background color.

Run your application and you will see all products displayed by the View. See the below image:

all products
Conclusion

I hope this introductory tutorial has given you some insights in to the topic of Tag Helpers. Now you are ready to implement Tag Helpers so check the next tutorial on Tag Helpers – Built-In Tag Helpers in ASP.NET Core.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.