Globally Configure Tag Helpers with ASP.NET Dependency Injection
Monday, February 8, 2016
Tag Helpers are simple to create and they help make ASP.NET MVC Razor views extremely readable. Recently I created a Tag Helper that needed to be globally configured with an API key so it can call an API.
In this article I'll discuss how to build a Tag Helper to display a GIF from Giphy; and how to use ASP.NET Core's built-in dependency injection to configure this Tag Helper at application startup.
The Giphy Tag Helper
The Tag Helper is fairly straight-forward. It's a giphy
tag with a search-term
attribute. Here's an example:
<giphy search-term="superman" />
This will display a random GIF related to the search term "superman". Behind the scenes, the Tag Helper calls the Giphy API to get a random URL based on the search term. We'll need an API key to call the API, so we need a way to globally configure it.
Here's the Tag Helper:
[OutputElementHint("img")]
public class GiphyTagHelper : TagHelper
{
private GiphyTagHelperConfiguration _config;
public GiphyTagHelper(GiphyTagHelperConfiguration config)
{
_config = config;
}
public string SearchTerm { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
string url = await GetGiphyUrl(_config.ApiKey, SearchTerm);
if (string.IsNullOrWhiteSpace(url))
{
output.SuppressOutput();
} else
{
output.TagName = "img";
output.TagMode = TagMode.SelfClosing;
output.Attributes["src"] = url;
}
}
private async Task<string> GetGiphyUrl(string apiKey, string searchTerm)
{
// ...
}
}
The constructor requires a GiphyTagHelperConfiguration
object. We'll get ASP.NET's built-in IoC container to provide it at runtime. (more on this later)
The SearchTerm
public property will be exposed as a search-term
attribute in the Tag Helper.
The core of the Tag Helper is quite simple. It'll use the API key from the config object and the search term to get a GIF URL from Giphy. If a URL is returned, it'll transform the Tag Helper to an img
tag and set its src
attribute to the URL. If it failed to get a URL, it'll hide the entire element (output.SuppressOutput()
).
The Configuration Object and Helper Extension Method
We need to create a simple configuration object to hold settings for the Tag Helper. For now, it'll only have an ApiKey property:
public class GiphyTagHelperConfiguration
{
public string ApiKey { get; }
public GiphyTagHelperConfiguration(string apiKey)
{
ApiKey = apiKey;
}
}
The goal is to create a singleton of this class and add it to the IoC container. We'll create an extension method on IServiceCollection
to do this:
public static class GiphyTagHelperExtensions
{
public static void AddGiphyTagHelper (this IServiceCollection services,
GiphyTagHelperConfiguration config)
{
services.AddSingleton(_ => config);
}
}
ASP.NET Core Configuration
Now it's time to go into the StartUp
class to hook everything up:
public class Startup
{
private readonly IConfiguration Configuration;
public Startup()
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
Configuration = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddGiphyTagHelper(new GiphyTagHelperConfiguration(Configuration["giphy:apiKey"]));
// ...
}
public void Configure(IApplicationBuilder app)
{
// ...
}
}
We're using the AddGiphyTagHelper()
extension method to do all the work to set up the IoC container with a GiphyTagHelperConfiguration
object containing the API key. The value is pulled out of an appsettings.json
file and can be overridden by an environment variable. For more information on how configuration works in ASP.NET Core, see this documentation page.
Now every instance of the GiphyTagHelper
will have access to the API key via the configuration object.
The Controller and Razor View
The MVC controller is super simple. The model is a class that contains a SearchTerm
property:
public class HomeController : Controller
{
public IActionResult Index(IndexModel model) => View(model);
}
And the view looks like this:
@model TagHelperDemo.Mvc.Models.IndexModel
@addTagHelper "*, GiphyTagHelper"
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<form asp-controller="Home" asp-action="Index" method="get" asp-antiforgery="false">
<input asp-for="SearchTerm" /> <button type="submit">Giphy!</button>
</form>
<giphy search-term="@Model.SearchTerm" />
</body>
</html>
Here's the Tag Helper in action:
Source Code
And here's the source code:
Tag Helpers are simple to create and they help make ASP.NET MVC Razor views extremely readable. Recently I created a Tag Helper that needed to be globally configured with an API key so it can call an API.
In this article I'll discuss how to build a Tag Helper to display a GIF from Giphy; and how to use ASP.NET Core's built-in dependency injection to configure this Tag Helper at application startup.
The Giphy Tag Helper
The Tag Helper is fairly straight-forward. It's a giphy
tag with a search-term
attribute. Here's an example:
<giphy search-term="superman" />
This will display a random GIF related to the search term "superman". Behind the scenes, the Tag Helper calls the Giphy API to get a random URL based on the search term. We'll need an API key to call the API, so we need a way to globally configure it.
Here's the Tag Helper:
[OutputElementHint("img")]
public class GiphyTagHelper : TagHelper
{
private GiphyTagHelperConfiguration _config;
public GiphyTagHelper(GiphyTagHelperConfiguration config)
{
_config = config;
}
public string SearchTerm { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
string url = await GetGiphyUrl(_config.ApiKey, SearchTerm);
if (string.IsNullOrWhiteSpace(url))
{
output.SuppressOutput();
} else
{
output.TagName = "img";
output.TagMode = TagMode.SelfClosing;
output.Attributes["src"] = url;
}
}
private async Task<string> GetGiphyUrl(string apiKey, string searchTerm)
{
// ...
}
}
The constructor requires a GiphyTagHelperConfiguration
object. We'll get ASP.NET's built-in IoC container to provide it at runtime. (more on this later)
The SearchTerm
public property will be exposed as a search-term
attribute in the Tag Helper.
The core of the Tag Helper is quite simple. It'll use the API key from the config object and the search term to get a GIF URL from Giphy. If a URL is returned, it'll transform the Tag Helper to an img
tag and set its src
attribute to the URL. If it failed to get a URL, it'll hide the entire element (output.SuppressOutput()
).
The Configuration Object and Helper Extension Method
We need to create a simple configuration object to hold settings for the Tag Helper. For now, it'll only have an ApiKey property:
public class GiphyTagHelperConfiguration
{
public string ApiKey { get; }
public GiphyTagHelperConfiguration(string apiKey)
{
ApiKey = apiKey;
}
}
The goal is to create a singleton of this class and add it to the IoC container. We'll create an extension method on IServiceCollection
to do this:
public static class GiphyTagHelperExtensions
{
public static void AddGiphyTagHelper (this IServiceCollection services,
GiphyTagHelperConfiguration config)
{
services.AddSingleton(_ => config);
}
}
ASP.NET Core Configuration
Now it's time to go into the StartUp
class to hook everything up:
public class Startup
{
private readonly IConfiguration Configuration;
public Startup()
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
Configuration = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddGiphyTagHelper(new GiphyTagHelperConfiguration(Configuration["giphy:apiKey"]));
// ...
}
public void Configure(IApplicationBuilder app)
{
// ...
}
}
We're using the AddGiphyTagHelper()
extension method to do all the work to set up the IoC container with a GiphyTagHelperConfiguration
object containing the API key. The value is pulled out of an appsettings.json
file and can be overridden by an environment variable. For more information on how configuration works in ASP.NET Core, see this documentation page.
Now every instance of the GiphyTagHelper
will have access to the API key via the configuration object.
The Controller and Razor View
The MVC controller is super simple. The model is a class that contains a SearchTerm
property:
public class HomeController : Controller
{
public IActionResult Index(IndexModel model) => View(model);
}
And the view looks like this:
@model TagHelperDemo.Mvc.Models.IndexModel
@addTagHelper "*, GiphyTagHelper"
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<form asp-controller="Home" asp-action="Index" method="get" asp-antiforgery="false">
<input asp-for="SearchTerm" /> <button type="submit">Giphy!</button>
</form>
<giphy search-term="@Model.SearchTerm" />
</body>
</html>
Here's the Tag Helper in action:
Source Code
And here's the source code: