Typed HttpClient Instances in .NET Core Web Applications
Http Client and Typed Instances

Typed HttpClient Instances in .NET Core Web Applications

In last article, we have seen how a named HttpClient instance can be useful. It allows to keep all configurations at single place. These configurations are associated with a name. Then the name can be passed as parameter to IHttpClientFactory.CreateClient method to obtain the named instance.

Conceptually, typed HttpClient instances also works on the same lines. But instead of using a string, it uses a type. In this blogpost, let’s see how to use typed HttpClient instances.

Typed vs Named Clients

As explained in previous post, a string can be used as key while configuring named HttpClient instances. Typed HttpClients also provide the same facility. But instead of using a string as a key, it enables to use a type as a key.

With named clients, we had to inject IHttpClientFactory so that CreateClient method can be called to create an HttpClient instance. This is where typed instances are a bit better. The registered type can directly be injected as dependency.

For ex. let’s say an application needs to call GitHub API and Google Maps API. A single dedicated type can be used for a single backend type, meaning a class GitHubApiConsumer and another class GoogleMapsApiConsumer can be created to call these backend APIs. These two classes will encapsulate all the necessary details which are required to call the respective backend service.

The caller does not need to know about IHttpClientFactory or any other HttpClient configurations.

How ?

Typed client basically means a type, which accepts HttpClient as a dependency in its constructor. Below code shows a type to call GitHub API. Not that, the HttpClient instance is not exposed to outside classes.

Below code does not specify any configurations like request headers or base address. For this demo, these settings are specified in Startup.cs.

public class GitHubApionsumer
{
private readonly HttpClient _httpClient;
public GitHubApionsumer(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<List<GitHubRepo>> GetRepos()
{
var response = await _httpClient.GetAsync("users/aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<List<GitHubRepo>>(responseStream);
}
}
view raw GitHubApiConsumer.cs hosted with ❤ by GitHub

Next code block is showing Startup.cs configurations and a HomeController.cs code showing how this typed client can be consumed.

// Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Use GitHubApiConsumer as key to the configurations
services.AddHttpClient<GitHubApionsumer>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "theCodeBlogger.com Demo");
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Request Pipeline…
}
}
// HomeController.cs
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly GitHubApionsumer _gitHubApionsumer;
// Notice that GitHubApiConsumer is directly injected – IHttpClientFactory is not injected.
public HomeController(ILogger<HomeController> logger, GitHubApionsumer gitHubApionsumer)
{
_logger = logger;
_gitHubApionsumer = gitHubApionsumer;
}
public async Task<IActionResult> Index()
{
List<GitHubRepo> repoCollection = await _gitHubApionsumer.GetRepos();
ViewBag.repoCollection = repoCollection;
return View();
}
}
view raw Startup.cs hosted with ❤ by GitHub

Opinion

I would personally prefer typed clients over named clients, because

  • Typed client can be injected directly
  • Typed clients encapsulates all the logic of calling backend API, thus also helping improving readability and maintainability of the application.

What is your opinion ? Let me know your thoughts.

Leave a Reply