A tag helper is any class that implements the ITagHelper
interface. However, when you create a tag helper, you generally derive from TagHelper
, doing so gives you access to the Process
method.
In your ASP.NET Core project, create a folder to hold the Tag Helpers called TagHelpers. The TagHelpers folder is not required, but it’s a reasonable convention. Now let’s get started writing some simple tag helpers.
-
Tag helpers use a naming convention that targets elements of the root class name (minus the TagHelper portion of the class name). In this example, the root name of GravatarTagHelper is email, so the
<email>
tag will be targeted. This naming convention should work for most tag helpers, later on I’ll show how to override it. -
The
EmailTagHelper
class derives fromTagHelper
. TheTagHelper
class provides methods and properties for writing Tag Helpers. -
The overridden
Process
method controls what the tag helper does when executed. TheTagHelper
class also provides an asynchronous version (ProcessAsync
) with the same parameters. -
The context parameter to
Process
(andProcessAsync
) contains information associated with the execution of the current HTML tag. -
The output parameter to
Process
(andProcessAsync
) contains a stateful HTML element representative of the original source used to generate an HTML tag and content.
GravatarTagHelper
using Microsoft.AspNetCore.Razor.TagHelpers; using System; using System.Security.Cryptography; using System.Text; using PSC.Enums; namespace PSC.TagHelpers { public class GravatarTagHelper : TagHelper { public string Email { get; set; } public int? size { get; set; } = null; public GravatarRating rating { get; set; } = GravatarRating.Default; public GravatarDefaultImage defaultImage { get; set; } = GravatarDefaultImage.MysteryMan; public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "img"; output.Attributes.SetAttribute("alt", Email + " gravatar"); var url = new StringBuilder("//www.gravatar.com/avatar/", 90); url.Append(GetEmailHash(Email)); var isFirst = true; Action<string, string> addParam = (p, v) => { url.Append(isFirst ? '?' : '&'); isFirst = false; url.Append(p); url.Append('='); url.Append(v); }; if (size != null) { if (size < 1 || size < 512) throw new ArgumentOutOfRangeException("size", size, "Must be null or between 1 and 512, inclusive."); addParam("s", size.Value.ToString()); } if (rating != GravatarRating.Default) addParam("r", rating.ToString().ToLower()); if (defaultImage != GravatarDefaultImage.Default) { if (defaultImage == GravatarDefaultImage.Http404) addParam("d", "404"); else if (defaultImage == GravatarDefaultImage.Identicon) addParam("d", "identicon"); if (defaultImage == GravatarDefaultImage.MonsterId) addParam("d", "monsterid"); if (defaultImage == GravatarDefaultImage.MysteryMan) addParam("d", "mm"); if (defaultImage == GravatarDefaultImage.Wavatar) addParam("d", "wavatar"); } output.Attributes.SetAttribute("src", url.ToString()); if (size != null) { output.Attributes.SetAttribute("width", size.ToString()); output.Attributes.SetAttribute("height", size.ToString()); } } private static string GetEmailHash(string email) { if (email == null) return new string('0', 32); email = email.Trim().ToLower(); var emailBytes = Encoding.ASCII.GetBytes(email); var hashBytes = new MD5CryptoServiceProvider() .ComputeHash(emailBytes); var hash = new StringBuilder(); foreach (var b in hashBytes) hash.Append(b.ToString("x2")); return hash.ToString(); } } }
GravatarDefaultImage
namespace PSC.Enums { public enum GravatarDefaultImage { /// /// The default value image. That is, the image returned /// when no specific default value is included /// with the request. /// At the time of authoring, this image is the Gravatar icon. /// Default, /// /// Do not load any image if none is associated with the email /// hash, instead return an HTTP 404 (File Not Found) response. /// Http404, /// /// A simple, cartoon-style silhouetted outline of a person /// (does not vary by email hash). /// MysteryMan, /// /// A geometric pattern based on an email hash. /// Identicon, /// /// A generated 'monster' with different colors, faces, etc. /// MonsterId, /// /// Generated faces with differing features and backgrounds. /// Wavatar } }
GravatarRating
namespace PSC.Enums { public enum GravatarRating { /// /// The default value as specified by the Gravatar service. /// That is, no rating value is specified /// with the request. At the time of authoring, /// the default level was <see cref="G"/>. /// Default, /// /// Suitable for display on all websites with any audience type. /// This is the default. /// G, /// /// May contain rude gestures, provocatively dressed individuals, /// the lesser swear words, or mild violence. /// Pg, /// /// May contain such things as harsh profanity, intense violence, /// nudity, or hard drug use. /// R, /// /// May contain hardcore sexual imagery or /// extremely disturbing violence. /// X } }
To make the GravatarTagHelper
class available to all our Razor views, add the addTagHelper
directive to the Views/_ViewImports.cshtml file:
@using AuthoringTagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, PSC
Now in your page, you have access to your gravatar tag!