Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

TagHelpers

0.00/5 (No votes)
15 Dec 2014 1  
This article talks about TagHelpers - a new feature added in ASP.NET vNext

Introduction

TagHelper is a new feature in ASP.NET MVC. If you haven’t already heard, TagHelpers have gained quite a bit of discussion among the techies, with some claiming the return of server side controls. Anyone remember:

<asp:TextBox id="txt1" runat="server">

I personally don’t see a problem with TagHelpers, it’s just another simplification in mixing HTML with server generated content without the baggage of control life cycles, view state, events, etc. In fact, I believe it is a bit more cleaner approach.

Disclaimer

This article is based on the beta version of ASP.NET 5 (or vNext). Things can and will change, so some of the information about TagHelpers might be out of date.

Purpose

There are already articles on TagHelpers – the brilliant ones are by Scott Hanselman and Jeffrey T. Fritz (see resources). This article adds on top as:

  1. It provides more up to date information based on the latest development build (v1.0.0-rc1-10798)
  2. It gives developer focused view of TagHelpers with more examples
  3. We go through building a sample project. It took me some time to figure out how the various pieces fit together as everything is constantly changing, and not well documented so it might save time for others

What are TagHelpers?

TagHelpers allow preprocessing of HTML attributes with server side content - that is:

<a asp-controller="Home" asp-action="About">About</a>

gets transformed to:

<a href="/Home/About">About</a>

Before dwelling deeper, let’s see how the current version of MVC behaves. This will also give us an appreciation of the need for TagHelpers.

In ASP.NET MVC 5, if we wanted to declare a link to another page (anchor tag), there are several options.

ActionLink

Perhaps the most common is using the HTML helper ActionLink method. There are several overloads, I am using the one that will let me set the action, controller and HTML attributes.

public static MvcHtmlString ActionLink(
        this HtmlHelper htmlHelper,
        string linkText,
        string actionName,
        string controllerName,
        Object routeValues,
        Object htmlAttributes
)

A simple usage would be:

@Html.ActionLink("About this site",
"About","Home",null,new { @class="someClass"})

Razor & HTML

Another option would be to mix n match this in razor syntax.

<a href="@Url.Action("About", 
"Home")" class="someClass">About this site</a>

We can also create our own Razor helpers or HTML helper extension methods.

While this is not bad, our scenario is simplistic, I am sure all of us know how tricky it can be to mix n match razor syntax with HTML. Another way of looking at this is, that in the first example we went razor first and added HTML attributes, whereas in the second instance, we went HTML first and added razor syntax.

AnchorTagHelper

This is where TagHelper come into the picture as we don't have to leave the comfort of HTML, and at the same time, we can utilize the power of C# server side. Considering the same example above, we can rewrite the anchor tag as:

<a asp-controller="Home" asp-action="About" class="someClass">About this site</a>

To simplify what happens next - MVC will pass this anchor to a C# class (AnchorTagHelper) that will inspect the attributes and output the server generated content. It’s a cleaner way of mixing HTML and C# code.

This is different to the ASP.NET server side controls even though the syntax/concept might look extremely familiar. The main differences are:

  • No life cycle events
  • No view state
  • No control state

Note: Some articles will refer to the use of controller and action attributes. However, there was a discussion on this issue and looks like out of the three popular approaches, the one with prefixing asp- has been selected in the current build. The other two options were to use @controller or just controller.

TagHelpers Namespace

ASP.NET already comes with a set of built TagHelpers. They live in the Microsoft.AspNet.Mvc.TagHelpers namespace and consists of:

  • Anchor
  • Input
  • Label
  • Select
  • TextArea
  • ValidationMessage
  • ValidationSummary
  • Form

We will take a quick look at all of these and their basic usage.

AnchorTagHelper

This tag will be applied to <a> anchor elements. At the moment, it is supports the following attributes:

  1. asp-action
  2. asp-controller
  3. asp-fragment
  4. asp-host
  5. asp-protocol
  6. asp-route

All of these are used to generate a URL for the href attribute of the anchor tag.

<a asp-controller="Home" asp-action="About">About</a>

If the href is already set in the <a> anchor HTML element, an exception will be thrown if the tag helper attributes are set. So for example, the below will throw an exception.

<a href="/Home/Index" asp-controller="Home" asp-action="Index">Home</a>

InputTagHelper

As the name suggests, this TagHelper is applied to <input> HTML elements. It is similar to the TextBoxFor HMTL extension method as it generates an input element bound to a property in the model. The input tag supports the following attributes:

  1. asp-for
  2. asp-format

The 'asp-for' attribute refers to a property in the model and is also used in various other tag helpers

The 'asp-format' applies the format after the value has been retrieved. This is useful for currencies, or date time values. For example (Birthday is a property on the model of type DateTime).

<input asp-for="Birthday" asp-format="{0:yyyy-MM-dd}" />

Note: The asp-for is of type ModelExpression, this is a new class in ASP.NET MVC 6 (vNext). The constructor takes a string parameter that evaluates to a property in the Model. We can also refer to nested objects - for example:

<input asp-for="Address.Street" type="text" /></div>

Contrast this with TextBoxFor:

@Html.TextBoxFor(model => model.Birthday)

At the moment, there is a problem with the MVC 6 model binder, as entering a invalid date (abc) will display an exception message.

The parameter conversion from type 'System.String' to type 'System.DateTime' failed. See the inner exception for more information.

In the MVC 5, the exception message is reprocessed to a more user friendly version as:

The value 'abc' is not valid for Birthday

LabelTagHelper

Same purpose as the HtmlExtension.LabelFor method - has only one attribute 'asp-for' used to define a property in the model (as discussed in InputTagHelper). It is applied to the <label> element.

<label asp-for="Birthday" />

SelectTagHelper

The SelectTagHelper applies to the <select> element and supports two attributes 'asp-for' and 'asp-items'. As discussed before, asp-for is used to define a property in the model, whereas asp-items is used to define a collection of values of type IEnumerable<SelectListItem>.

<select asp-for="Country" asp-items="ViewBag.Countries">

To add a default item, we can do this:

<select asp-for="Country" asp-items="ViewBag.Countries">
     <option selected="selected" value="">Choose Country</option>
</select>

Just for comparison, the HtlmHelper way of doing this:

@Html.DropDownListFor(m=>m.Country, (IEnumerable<SelectListItem>)ViewBag.Countries)

The asp-items can evaluate to anything available to the view - it could be a property on the object, variable, etc.

We could declare in the view a variable:

@{
    SelectListItem[] items =
    {
        new SelectListItem() { Text = "item 1" },
        new SelectListItem() { Text = "item 2" }
    };
}

and then use that as asp-items:

<select asp-for="Country" asp-items="items">

TextAreaTagHelper

Processes the <textarea> element - supports only one attribute asp-for, where Information is a property on the:

<textarea asp-for="Information"></textarea>

ValidationMessageTagHelper

This tag helper is used for displaying the validation-error message. It has the same purpose as the ValidationMessageFor HTML Helper. The interesting question here might be which HTML element it applies to? The ValidationMessageFor extension method generated a <span> element, similarly the ValidationMessageTagHelper applies on the <span> element.

<span asp-validation-for="Birthday" />

It has only one attribute asp-validation-for, which represents a field on the Model.

<input asp-for="Birthday" asp-format="{0:yyyy-MM-dd}" />
<span asp-validation-for="Birthday" />

Note: There is a new attribute called TagName that links a C# class with the HTML tag on which it is applied.

[TagName("span")]
public class ValidationMessageTagHelper : TagHelper

ValidationSummaryTagHelper

Used to display the summary of validation errors - like the HTML extension method ValidationSummary. It only supports one attribute asp-validation-summary that can have one of the following values:

  • None: No validation messages displayed
  • ModelOnly: Displays only the Model errors - not the property ones
  • All: Displays all messages

The asp-validation-summary is applied to a div element.

<div class="validation" asp-validation-summary="ModelOnly"/>

FormTagHelper

Used to generate a <form> element. It supports the following attributes which are self explanatory.

  1. asp-action
  2. asp-controller
  3. asp-anti-forgery

This is similar to the HTML helper BeginForm method.

<form asp-action="FormSave" 
asp-controller="Home" asp-anti-forgery="true">

If the action attribute is specified on the form tag with the asp- attributes, it will throw an InvalidOperationException.

Putting it all together

<form asp-action="FormSave" 
asp-controller="Home" asp-anti-forgery="true" method="post" >
    <div>
        <label asp-for="Name" />
        <input asp-for="Name" type="text" />
        <span class="validation" asp-validation-for="Name" />
    </div>
 
    <strong>Validation Errors</strong>
    <div class="validation" asp-validation-summary="ModelOnly"/>
</form>

Custom TagHelpers

TagHelpers can be extended – like everything else. So we can create our own TagHelpers to augment our HTML controls. There is already an article discussing creation of TagHelper for Kendo date picker.

How to Start using TagHelpers

The two basic steps required to use TagHelpers is:

  1. Add reference to Microsoft.AspNet.Mvc.TagHelpers
  2. Add @addtaghelper "Microsoft.AspNet.Mvc.TagHelpers" keyword in our view where we want to use the tag helpers.
  3. The @addtaghelper can also be added to the _Viewstart.cshtml so it is available to all the views.

If you are having difficulties in getting this to work, follow the sample project below.

Project

Let’s now dig into a small project that will use both these attributes. The project was built using Visual Studio 2015 preview. There is also a section on building and running this without using Visual Studio near the end.

Source

The project source is available at github here.

If you download the project and build using Visual Studio, please set the latest version of the KRE-CLR runtime otherwise the project will not build, following the steps in the section Latest Version below.

If you receive the error, "Could not find the Microsoft.AspNet.Loader.Interop nuget package in the packages folder of the current solution" - close Visual Studio and open the project again, it should work.

Latest Version

It’s important to realize, that ASP.NET vNext is in a constant state of changes & updates. As such, when I downloaded and installed Visual Studio, the TagHelper changes were not available in the CLR. So, there are some perquisites to connect to the development feed and download the latest NuGet packages.

Install KVM

We will need to get the latest version of the CLR runtime. For that, we need to install KVM – this can be done by running the following in command prompt:

<code>@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex 
((new-object net.webclient).DownloadString
('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

Updating KRE Runtime

I found that KVM was using the NuGet feed to install the latest version of the runtime (https://www.nuget.org/api/v2) which at this time did not contain the TagHelper changes. I had to change the feed to https://www.myget.org/F/aspnetvnext/api/v2/.

I looked at the kvm.ps1 file (at %userprofile%\.kre\bin\) and found it was using an environment variable KRE_NUGET_API_URL. So I had set it by:

  1. Opening a new power shell window
  2. Running the following command:

$env:KRE_NUGET_API_URL = “https://www.myget.org/F/aspnetvnext/api/v2/

In the same PowerShell window, run the following command to download and install the latest version of the CLR from the ASP.NET development feed.

kvm upgrade

To see the installed CLR, run the following command:

kvm list

Creating a New Project

Create a new ASP.NET Web Application. Check the “Create directory for solution”, so everything required is inside the solution. In the next screen, select the ASP.NET 5 Empty project.

Update NuGet Feed in Visual Studio

We need to update the NuGet feed so the latest .NET packages can be downloaded. This is done by going into Tools -> NuGet Package Manager-> Package Manager Settings. Add a new package source, set the source as https://www.myget.org/F/aspnetvnext/api/v2/ and Name as ASP.NET vNext, and click Update.

Set KRE CLR Version

By default, Visual Studio uses the default KRE version from NuGet feed which at the time of writing this article is 1.0.0 beta 1. Not all the new options are available in this version. We will change this to the latest version which (now) is KRE-CLR-x86.1.0.00-rc1-10781. If you only see one version, make sure to have followed the steps to update the KRE. Also, the version you will see depends on the current build.

Add References

The next step is to add the references. Open project.json and add the following under dependencies.

"Microsoft.AspNet.Server.IIS": "1.0.0-rc1-10778",
"Microsoft.AspNet.Server.WebListener" :  "1.0.0-rc1-11230"
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-12143",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-12143"

The first dependency allows hosting our application in IIS, the second one support self hosting. The other two are self explanatory.

Enable MVC

In Startup.cs:

Add the following using statement:

using Microsoft.Framework.DependencyInjection;

Add the following in the method Configure:

app.UseServices(m => { m.AddMvc(); });
app.UseMvc();

Add Controllers

Create a folder called Controllers, and add a new controller class called HomeController. Add the following two methods:

public IActionResult Index()
{
     return View();
}

public IActionResult About()
{
   return View();
}

Add Views

Create a folder called Views, and inside, add another folder called Home. Inside Home add two new MVC View Pages:

  1. Index.cshtml
  2. About.cshtml

Index.cshtml

@addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"

<h2>TagHelper test website</h2>

<ul>

    <li>
        <a asp-controller="Home" asp-action="About">Anchor tag</a>
    </li>
</ul>

About.cshtml

@addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"

<h2>About page</h2>

<p>This website is created to show case the new TagHelper functionality in Asp.Net vNext
</p>

<p>
    <a asp-controller="Home" asp-action="Index">Back</a>
</p>

Run

If you run the project, you should be able to see the tag helpers in action.

Without using Visual Studio

Let’s say you are going all ninja, and would like to build (& run) the project without using Visual Studio. If the answer is yes, keep reading.

Note: Please update KRE to the latest version following the steps mentioned earlier in Install KVM.

Update NuGet for KPM

If you are planning on restoring packages using KPM command line, it is important to update the NuGet feed source. This can be done as follows:

  1. Browse to %appdata%\NuGet and open the file Nuget.config.
  2. Under package sources, add a new node as follows:
    <add key="aspnet5 " value="https://www.myget.org/F/aspnetvnext/api/v2/" />
  3. Save

Run

  1. Open a new powershell
  2. Browse to the src folder for the project – for example, if the project is under c:\Development, browse to c:\Development\TagHelperSample\src\TagHelperSample.
  3. Change the powerscript to use the latest version of KRE CLR. You can run the command kvm list to see the available CLRs and choose the latest version from the dev branch. If you only see one CLR – it is probably because KRE feed has not been updated. Please do this by following the steps mentioned earlier in Install KVM.
    kvm use 1.0.0-rc1-10781
  4. Restore the packages by running the following command:
    kpm restore
  5. Run the project by using the following command:
    k  Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener 
    --server.urls http://localhost:5001

If you browse to http://localhost:5001 - the website should be available.

Resources

History

  • 16/12/2014 - First version
  • 18/12/2014 - Added additional details about TagHelper classes

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here