A few days ago I wrote a blog post about how I got started writing my first ASP.NET Tag Helper that delivered a Kendo UI DatePicker widget. I realize that I rambled through the features of the tag helper, and in this article I want to cover in detail each of the features currently available in ASP.NET vNext Tag Helpers.
NOTE: This is the third part of a series of posts introducing ASP.NET MVC Tag Helpers. The other articles in the series are:
I didn’t go into planning this blog post to be a bit of a documentation piece, but it has turned out that way. I think these tag helpers are an important feature for developers to be productive with ASP.NET, and decided to leave this post in its “documentation-like” form.
Getting Started
First things first, to build a tag helper you need to declare a tag helper as a class that inherits from the abstract class Microsoft.AspNet.Razor.Runtime.TagHelpers.TagHelper class. There are two virtual methods in this class that you can override: Process and ProcessAsync.
Process and ProcessAsync have a similar signature string:
public override void Process(TagHelperContext context, TagHelperOutput output)
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
… and they do the same thing: manage the generation of content for your tag helper on the server before it is transmitted to the client. This is where you as the tag helper author will be doing the majority of your work. However, there are other features that you may want to consider before plowing into formatting your content to be delivered.
Tag Helpers, like all of ASP.NET are built with dependency injection in mind. This means that you can add any property you would like to your class and mark it with an ActivateAttribute and the ASP.NET runtime will deliver to your property the object you requested, provided it is registered with the dependency injection provider.
Take a look at this:
[Activate]
protected internal ViewContext Context { get; set; }
Now we can pick up the ViewContext that I might normally work with in a razor view directly inside of my tag helper. I now have access to information about the Controller, the Action, the Model, all of that good stuff. Neat!
How to Identify Where and How the Tag Helper should Take Action
The last thing we need to configure before building out the content of the tag helper is how the tag helper will interact with the view. This is accomplished in two ways:
- By naming convention
- With the TagNameAttribute
If you name your tag helper “FooTagHelper”, the framework will inject the tag helper for a tag with element name “foo”:
<foo id="stuff"/>
That’s cool, but if I want to be more declarative about the tag name, I can use the TagNameAttribute and pass in a collection of strings to identify which tag names you would like the helper to act on:
[TagName("select")]
Processing My Content
Finally, lets look at the objects and options available to process our content in the Process methods. The first argument passed in is a Microsoft.AspNet.Razor.Runtime.TagHelpers.TagHelperContext This is handy because it only gives you access to the AllAttributes collection. This collection is a Dictionary<string,object> with all of the attributes that the developer set on your tag helper. You can also build public properties on your class and the attribute values with matching names in the markup will be passed appropriately to your class.
The other parameter passed to the Process method is a Microsoft.AspNet.Razor.Runtime.TagHelpers.TagHelperOutput. It is on this parameter that you can control how and what is delivered into the razor output. Taking a look at the features of this object gives us the following:
Attributes: This is the output collection of attributes as a Dictionary<string,object>. Add and manipulate this content based on what you need in your HTML on the tag being output.
Content: This is a string that contains all markup to be delivered between the start and end tags of your tag helper.
SelfClosing: This boolean property indicates if your tag should be self closing or not.
TagName: This is the output element name for your tag. This allows you to change the tag in razor markup from to . The hidden feature behind this property is that you can set the TagName to the empty string and the tag helper will emit no begin and end tags. This is very handy when you want to emit markup with sibling elements, like an input tag next to a script tag.
The methods on this object assist in generating the tag elements: GenerateStartTag, GenerateEndTag, and GenerateContent. If you are emitting a wrapper tag with content inside of it, you will need to call these methods to build out your markup.
Summary
The tag helper feels like an evolution of the Control object from web forms. You are enabled to only maintain the content within the scope of the tag on the razor page, but you can build any content you want inside of that element. In my next post, I’ll show you how we can override standard HTML tags to add features to dummy-proof your applications for your developers.