ASP.NET Core Tag Helpers for Bootstrap

The ASP.NET Core tag helpers improve on the HTML templated helpers in ASP.NET MVC 5. ASP.NET Core comes with some useful stock tag helpers for common tasks such as creating custom elements or extending existing HTML elements, but their use can be extended to making a framework such as Bootstrap easier to work with. Dino shows how helpers are used, and demonstrates a Bootstrap Modal Tag Helper

The pipeline is the one part of ASP.NET Core that is really different from the old ASP.NET. This affects the way that you code a few of the essential routine chores of web applications such as user authentication, error handling, and initial configuration. The rest of ASP.NET hasn’t changed so radically: Routing and model binding follow the same pattern as in past versions, though with a slightly enriched syntax. It is safe enough to say that once you’ve reached the realm of controllers and views you can literally take your previous code and migrate it seamlessly to ASP.NET Core.

I can be fairly hopeful of successfully porting small applications to ASP.NET Core with no significant effort as far as the user interface is concerned. However, just because those old Razor views might work almost verbatim under the new ASP.NET Core runtime doesn’t mean that you should leave them alone. The ASP.NET Core Razor engine has plenty new to offer. If you loved HTML templated helpers in ASP.NET MVC 5, then you’ll love ASP.NET Core tag helpers. And if you’re new to ASP.NET Core, or just didn’t much like HTML templated helpers, I’m fairly sure you’re going to love tag helpers because, well, they’re just a great piece of software that enables you to raise the abstraction bar of your views noticeably.

HTML and Razor Views

A Razor view is a text file that is made of HTML5 elements and C# code snippets. The text file, usually created with a CSHTML extension, is processed by an internal parser and dynamically turned into a C# class similar to below:

The code results from the following Razor markup:

As you can see, there are two types of items that the parser recognizes in the source file: there are the static items such as plain HTML including carriage returns, and there are also C# snippets. It’s surely enough to produce good views as years of experience with classic ASP.NET MVC proves, but it’s not necessarily a highly expressive and productive way of describing views. In ASP.NET Core, tag helpers are simply introduced as a third type of text item that the Razor parser can identify in the template. Technically, a tag helper is a C# class that is compiled to an assembly that is linked to the view through a new ad hoc directive @addTagHelper. When the parser then encounters a tag helper reference all it does is to invoke the underlying class and ask it to generate the actual HTML5 markup to emit. Tag helpers are executed in server-side code that can be bound to one or more markup elements, both HTML5 elements and custom elements. The server-side code can inspect the DOM of the element and possibly alter the existing markup or create ad hoc markup to be emitted on the fly.

Tag Helpers in Action

The major benefit of using tag helpers is to raise the level the expressivity of the Razor template file as much as you require. The ASP.NET Core team delivered a few stock tag helpers, as required for common tasks: Some of them refer to custom elements and others extend existing HTML elements. Let’s see a couple of quick examples and then proceed with a more sophisticated example that proves the real power of such helpers.

As you can see, the SCRIPT tag contains a custom attribute named asp-append-version. If this is emitted verbatim to any browser, it will be blissfully ignored unless there is some JavaScript code that exists within the page that can retrieve and interpret it. The net effect of that weird attribute will change entirely if you add the following directive to the Razor view.

This line instructs the parser to match the list of supported helpers in the given package with those found in your view. It so happens that one of the tag helpers coded in the built-in package knows how to handle the asp-append-version attribute. As a result, the parser calls the tag helper class and the tag helper class modifies the markup as below:

The link passed to the browser contains a hash value that changes whenever the content changes; so that the browser gets a fresh version when there’s fresh content. Here’s another example.

The ENVIRONMENT element is not part of HTML5 but as long as you have a tag helper registered for it, the emitted markup can be modified on the server-side. The net effect of the code above is that, if the current environment doesn’t match the value of the Names attribute, no JavaScript link is sent to the browser. You could have achieved the same in many other ways. For example, in this way.

The major benefit of tag helpers is to aid expressivity and render code more readable. For more basic information about tag helpers, check out http://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro.

Using Tag Helpers to Simplify Bootstrap Development

Bootstrap is an immensely useful library that lets you treat rich user-interface elements as if they were part of the native HTML syntax. With Bootstrap you can easily add tabstrips or dropdown boxes by simply creating some ad hoc DIV structure and using proper CSS classes. Everyone knows how to do that or, much more likely, knows how to figure it out via Google and StackOverflow links. No matter how much Bootstrap do you do every day, I’d bet that you can’t write a Bootstrap modal window without checking out first some documentation. That’s mostly because the HTML syntax is quirky and it has to be quirky because HTML native elements are too basic for such a sophisticated concept as a modal window. So what if, instead, the syntax to write a modal popup were like this?

I’m sure that this would be much easier to remember and learn. To turn this pseudo-code into the actual plain HTML that a browser can understand (with the aid of Bootstrap JavaScript and CSS files), you need an ad hoc tag helper. By the way, the final HTML the browser receives looks the following.

Writing the Bootstrap Modal Tag Helper

Firstly, let’s make sure the project has a _ViewImports.cshtml file with the following line of code:

BsTags just happens to be the name of the project and the name of the resulting assembly. The directive makes the Razor parser aware of all the tag helper classes defined in the assembly. To process a markup segment like the <modal> block above, you need a few helpers. By the rule of thumb, you need one tag helper class per custom markup element. The table below shows the mapping between markup elements and tag helper classes in the example:

Markup Element

Tag Helper Class

modal

ModalTagHelper

toggle

ToggleTagHelper

content

ModalContentTagHelper

header

ModalContentItemTagHelper

body

ModalContentItemTagHelper

footer

ModalContentItemTagHelper

Note that the innermost elements (header, body, footer) are processed by the same helper. Let’s take a look at the helper for the root class of the custom Razor markup.

A tag helper class inherits from TagHelper and is decorated by the HtmlTargetElement attribute that expresses the binding between the transformation code—the Process method—and the markup element—modal. The context parameter the Process method receives context information such as any optional information from a parent node and the original Razor DOM. The output parameter refers to the modified Razor DOM as modified by the helper.

To start with, the ModalTagHelper class changes the MODAL element to a DIV element. This is the optional container DIV that you might want to have in order to wrap up the modal and its trigger as a single tree. The MODAL element is expected to have an ID attribute and an AutoClose attribute to denote whether the close button should be generated. After checking for that, the Process method prepares a custom container with data to be passed down to the helpers of child elements and removes from the outermost actual DIV helper-specific attributes.

Next, the parser gets to process the TOGGLE element. The TOGGLE element is turned into a BUTTON element with the ID attribute set to the ID passed along the via the context.

Note that the extended format of the HtmlTargetElement attribute. The ToggleTagHelper class applies only to elements named TOGGLE child of an element named MODAL. Bootstrap-specific attributes for modal windows are added, such as data-toggle and data-target.

The ModalContentTagHelper class is the most sophisticated tag helper in this example. This reflects from the prototype of the Process method which is now asynchronous. The issue is that the ProcessAsync method needs to first recursively retrieve the markup being generated for the content of the CONTENT element that it works for. The reason is that, due to the expected Bootstrap DOM, the child content must be wrapped in a couple of nested DIVs, labeled with modal-dialog and modal-content classes. Those two DIV elements are an implementation detail and serve no explicit functional goal. There’s no need to replicate them in any higher-level language to describe a modal window. Incidentally, just saving this kind of code is the primary purpose of a language tool such as tag helpers.

The GetChildContentAsync method processes the entire child content, and returns the output as a plain HTML string. The method builds the wrapper Bootstrap DIV decorated with the modal class and sets its HTML content as appropriate.

Finally, the ModalContentItemTagHelper class turns HEADER, FOOTER and BODY markup tags into DIV elements just decorated with the required Bootstrap CSS class. Only in this class is recursive processing of the child content required, because you want to grab the entire HTML to display in the popup window and its header and footer. This is the place to intervene to support the auto-close icon in the header. Here’s the full source code of the method ProcessAsync.

If the autoclose attribute is specified, not just the close button is added to the header of the popup but also a dismiss ‘OK button is placed automatically on the footer. The MODAL code snippet shown earlier in the article produces just the screenshot in the figure.

Summary

Tag helpers are a cool new feature in ASP.NET Core, and are definitely a feature you will want to use extensively once you decide to jump on the ASP.NET Core. Personally, I wouldn’t state at all that this, and other similar cool pieces of technology, are enough to justify the move to Core. This is more likely to be a call that belongs to the project owners. One further word of caution about tag helpers is that they’re not a ‘free lunch’. Any Razor view is compiled on the fly (or it can be precompiled before production) and once it is compiled, it doesn’t matter whether its source code was created directly with plain HTML, or through sophisticated and much more expressive tag helpers. If your views are compiled on the fly, the more helpers you use and so the more it takes to generate the actual markup the first time the view is compiled or recompiled after live changes to the file. There’s probably no need to call here for a performance hit—not at all—but it’s generally better to figure out how it works before using something new.