CheapASPNETHostingReview.com | Best and cheap ASP.NET Core 1.0 hosting. In this post we will discuss about using TagHelpers in ASP.NET core 1.0. Well as you know the latest release of ASP.NET MVC has a new feature called TagHelpers. Let’s see what trouble we can get into today by creating hyperlinks that think for themselves.
Highly RECOMMENDED ASP.NET Core 1.0 Hosting Click Here
For example, when you want to create a home link the users can navigate back to th[kkstarratings]e home page. Using TagHelpers, a simple one would look like this:
1 | <a asp-controller="Home" asp-action="Index" title="Back to home page">Home Page</a> |
These attributes are part of the TagHelper classes “shipped” with the latest ASP.NET MVC 6 source code. Then when you run your web app, the LinkTagHelper renders out to this :
1 | <a title="Back to home page" href="/">Home Page</a> |
What’s Available?
Currently, there are 12 TagHelpers available to get you started. They are:
- AnchorTagHelper – Render a hyperlink
- CacheTagHelper – Allows you to wrap HTML code and implement various caching methods on that HTML.
- EnvironmentTagHelper – Renders different HTML based on a test vs. staging vs. production environment.
- FormTagHelper – Render a standard HTML form.
- ImageTagHelper – Render an image.
- LabelTagHelper – Render a Label
- LinkTagHelper – Render a <link> tag for CSS files.
- OptionTagHelper – Renders an <option> tag for a <select> (dropdown) tag.
- ScriptTagHelper – Renders a <script> tag for JavaScripts in the header or body.
- SelectTagHelper – Render a <select> (dropdown) tag.
- ValidationMessageTagHelper – Render a message for input validation
- ValidationSummaryTagHelper – Render out a Summary of all validations that didn’t pass when the form was submitted.
These come with ASP.NET MVC 6 right out of the box and ready to use.
How To Creating a Custom TagHelper
Make a “Fingerprint
- Created a brand new ASP.NET MVC 6 project and selected the ASP.NET 5 Preview in 2015.
- Created a TagHelper folder in the root of the project.
- Created a new class called SmartLinkHelper and started thinking about this SmartLink class.
First off, we don’t need to exert ourselves when we already have an AnchorTagHelper available.
Let’s use that.
1 2 3 4 5 | [TargetElement("a", Attributes = SmartLinkAttributeName)] public class SmartLinkHelper: AnchorTagHelper { private const string SmartLinkAttributeName = "smart-link"; } |
Every TagHelper has to have a “fingerprint” so .NET can identify the tags it needs to render. The fingerprint for our SmartLink is the anchor tag (‘a’) and a “smart-link” attribute. Our smart link will have the following signature:
1 | <a smart-link href="http://www.cnn.com/">Valid Link (to cnn.com)</a> |
Everything will be the same for our anchor tags, but we will add a “smart-link” attribute to identify it to .NET on which class to call when rendering our smart link. You can even define your own custom tag.
We need to add a Url attribute for external sites.
1 2 3 4 5 6 7 8 | [TargetElement("a", Attributes = SmartLinkAttributeName)] public class SmartLinkHelper: AnchorTagHelper { private const string SmartLinkAttributeName = "smart-link"; public SmartLinkHelper(IHtmlGenerator generator) : base(generator) { } [HtmlAttributeName("href")] public string Url { get; set; } |
Any property in your TagHelper class can become an attribute. All you need to do is place the HtmlAttributeName attribute on your property with a name of the attribute and you’re ready to go.
We Need Process!
Once we set up everything, the TagHelper needs a way to kick off the rendering process. This is where the Process and/or ProcessAsync methods come into play.
The Process and ProcessAsync methods take two parameters: a TagHelperContext and a TagHelperOutput.
- TagHelperContext contains all of the attributes and details about the tag that we’re working with in this TagHelper.
- TagHelperOutput is the buffer of what will be rendered to the browser. Think TagBuilder from a HtmlHelper.
Here is what we have so far with our ProcessAsync method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { // Grab the content inside the anchor tag. var child = await context.GetChildContentAsync(); var content = child.GetContent(); // Get the status of the page. var statusCode = await GetStatusCode(); // If we get a 404, remove the link. if (statusCode == HttpStatusCode.NotFound || statusCode == HttpStatusCode.InternalServerError) { RemoveLink(output, content); // Log a bad link or site if you want. return; } MergeAttributes(context, output); // Business as usual await base.ProcessAsync(context, output); } |
First, we grab the content inside the anchor tags. This is considered your “Content.”
Next, we perform an HttpClient Asynchronous request to the webpage and return the status code. We check to see if we have an internal server error (500) or the page wasn’t found (404). If we have either of those, we remove the link.
If we don’t have an error, we continue along grabbing all of the attributes on our new smart link tag and merge them.
Finally, we return the link.
To the View!
When implementing your TagHelpers in your Views, you need to include an @addTagHelper with the base TagHelper class and your project’s tag helper (My project is called SmartLinksDemo). These need to be at the top of your page
1 2 | @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, SmartLinksDemo" |
I also added this HTML to the bottom just for a simple demonstration.
1 2 3 4 5 6 7 8 9 10 11 12 | <hr/> <div class="row"> <div class="col-md-12"> <h2>Smart Link Demo</h2> <ul> <a title="Back to home page" href="/">Home Page</a> <li><a asp-controller="Home" asp-action="Index" title="Back to home page">Home Page</a></li> <li><a smart-link href="http://www.cnn.com/">Valid Link (to cnn.com)</a></li> <li><a smart-link href="javascript:void(0);">Bad Link on purpose</a></li> </ul> </div> </div> |
Once you have this HTML included in your View, you are ready to test out your SmartLink TagHelper.
Finish it!
Here is our final SmartLink TagHelper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | [TargetElement("a", Attributes = SmartLinkAttributeName)] public class SmartLinkHelper: AnchorTagHelper { private const string SmartLinkAttributeName = "smart-link"; public SmartLinkHelper(IHtmlGenerator generator) : base(generator) { } [HtmlAttributeName("href")] public string Url { get; set; } public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { // Grab the content inside the anchor tag. var child = await context.GetChildContentAsync(); var content = child.GetContent(); // Get the status of the page. var statusCode = await GetStatusCode(); // If we get a 404, remove the link. if (statusCode == HttpStatusCode.NotFound || statusCode == HttpStatusCode.InternalServerError) { RemoveLink(output, content); // Log a bad link or site if you want. return; } MergeAttributes(context, output); // Business as usual await base.ProcessAsync(context, output); } private static void MergeAttributes(TagHelperContext context, TagHelperOutput output) { // Merge the attributes and remove the smart-link and activate attributes. var attributesToKeep = context.AllAttributes .Where(e => e.Name != SmartLinkAttributeName) .ToList(); if (!attributesToKeep.Any()) return; var attributes = context.AllAttributes.Except(attributesToKeep); foreach (var readOnlyTagHelperAttribute in attributes) { output.Attributes.Add(new TagHelperAttribute { Name = readOnlyTagHelperAttribute.Name, Value = readOnlyTagHelperAttribute.Value, Minimized = readOnlyTagHelperAttribute.Minimized }); } } private static void RemoveLink(TagHelperOutput output, string content) { output.PreContent.SetContent(String.Empty); output.TagName = ""; output.Content.SetContent(content); output.PostContent.SetContent(String.Empty); } private async Task<HttpStatusCode> GetStatusCode() { try { using (var client = new HttpClient()) { var msg = new HttpResponseMessage(); await client.GetAsync(Url); return msg.StatusCode; } } catch { return HttpStatusCode.InternalServerError; } } } |
Conclusion
TagHelpers are slowly growing on me. I was skeptical at first whether they would be a benefit to me or not, but I would consider TagHelpers to be the WebControls from the WebForm days and even consider them on the same level as Angular Directives where you can create your own HTML tags.
However, with that said, TagHelpers can be loaded controls. If you wanted to build a <grid> TagHelper, there is nothing stopping you from creating a new WebGrid control, but there would be a LOT of code behind the scenes to generate a webgrid.