ASP.NET Core Email Tag Helper

Tag helpers enable server side code to generate HTML elements in Razor files. ASP.NET Core provides a number of tag helpers built in for generating html elements.

<!-- Anchor Tag Helper -->
<a asp-controller="Demo" asp-action="Register">Example Anchor Tag Helper</a>

When the razor page is generated then the following html is rendered in place of the tag helper

<a href="/Demo/Register">Example Anchor Tag Helper</a>

ASP.NET Core allows you to create custom tag helpers that you can then integrate into your project.

Creating a Custom Tag Helper

A common issue when creating a web site is to provide an email link that the user can click on. The email is a normal anchor tag where the href attribute starts with mailto: and then the email address. The email address should be converted into html entities to help prevent the email address being scraped.

Email Address (plain text)

<a href="mailto:myemailaddress@hotmail.com">Send Email</a>

Email Address (html characters)

<a ;&#x3A;&#x6D;&#x79;&#x65;&#x6D;&#x61;&#x69;&#x6C;&#x61;&#x64;&#x64;&#x72;&#x65;&#x73;&#x73;&#x40;&#x68;&#x6F;&#x74;&#x6D;&#x61;&#x69;&#x6C;&#x2E;&#x63;&#x6F;&#x6D;">Send Email</a>

Custom Email Tag Helper

Below is the email tag helper class that we are going to create.

  • The Attribute HtmlTargetElement sets the name we will use in the Razor code. It can be omitted in which case the Tag Helper naming convention is used by taking the class name with or without TagHelper. So to use it in a razor page it would be the email element
  • A Tag Helper must implement Process or ProcessAsync. Passed into these method is a TagHelperContext and TagHelperOutput
    • TagHelperContext - gives the context and information associated with executing the html tag
    • TagHelperOutput - contains the html element stateful information
  • The first step is to set what element needs creating from the tag helper. In this case the element is going to be the anchor attribute a. This is done by setting the output Tag Name
  • The next step is to set any attributes on the tag that need rendering. In order to send an email the attribute "href" is set with a value by calling Output.Attributes.SetAttribute(name,value). You can set as many attributes as your require
  • Finally the class needs to set the content that is rendered between the html tag. This can be done with a call to Output.Content.SetHtmlContent(value) or Output.Content.SetContent(value).
using Microsoft.AspNetCore.Razor.TagHelpers;

[HtmlTargetElement("email")]
public class EmailTagHelper : TagHelper
{
	public string Address { get; set; }
	public string LinkText { get; set; }
	public bool EncodeHtmlChars {get;set;} = true;

	public override void Process(TagHelperContext context, TagHelperOut\output)
	{
		output.TagName = "a";
		var txt = EncodeHtmlChars
            ? ConvertToHTMLEntities(Address.Trim())
            : Address.Trim();
		output.Attributes.SetAttribute("href",txt);
		output.Content.SetHtmlContent(LinkText.Trim());
	}

	private string ConvertToHTMLEntities(string inputStr)
	=> string.Join("", inputStr.ToCharArray().Select(c => string.Format("&#{0};", (int)c)).ToArray());
}

Installing and Using the Tag Helper

To use your custom tag helper ASP.NET Core needs to know where to load your Tag Helpers from. This is done by adding the following line to the _ViewImports.cshtml file.

  • @addTagHelper Lotushope.TagHelpers, LotushopeApp

The above line tells the web application the namespace and the assembly to search for tag helpers in.

Tag Helper Writer

Once you have created your tag helper you may want to unit test or see the results of the tag helper without having to render the razor page in production. The class TagHelperWriter (below) takes a TagHelper and the TagName that you want to render. It then calls the Process() method on the tag helper and writes the rendered content to a string.

public class TagHelperWriter
{

	public string Render<T>(T tagHelper, string tagName) where T : TagHelper
	{
		var tagHelperContext = GetTagHelperContext(tagName);
		var tagHelperOutput = GetTagHelperOutput(tagName);
		tagHelper.Process(tagHelperContext, tagHelperOutput);
		return renderTagHelperOutput(tagHelperOutput);
	}

	private TagHelperContext GetTagHelperContext(string tagName)
	{
		return new TagHelperContext(
			tagName,
			new TagHelperAttributeList(),
			new Dictionary<object, object>(),
			Guid.NewGuid().ToString("N"));
	}
	private TagHelperOutput GetTagHelperOutput(string tagName)
	{
		return new TagHelperOutput(
			tagName,
			new TagHelperAttributeList(),
			(result, encoder) =>
			{
				var tagHelperContent = new DefaultTagHelperContent();
				tagHelperContent.SetHtmlContent(string.Empty);
				return Task.FromResult<TagHelperContent>(tagHelperContent);
			});
	}
	private string renderTagHelperOutput(TagHelperOutput output)
	{
		HtmlEncoder encoder = HtmlEncoder.Create();
		using (var writer = new StringWriter())
		{
			output.WriteTo(writer, encoder);
			return writer.ToString();
		}
	}
}

Using Tag Helper Writer to see the Rendered Content

The following snippet of code uses the TagHelperWriter class to render the email tag helper to a string and then show the output in the console window of LINQPad

void Main()
{
	var renderer = new TagHelperWriter();
	var tag = new EmailTagHelper
    {	Address="mailto:myemailaddress@hotmail.com",
     	LinkText="Send Email"
    };

	var output = renderer.Render(tag,"email");
	output.Dump();
}