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.
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.
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
|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");|
|using var responseStream = await response.Content.ReadAsStreamAsync();|
|return await JsonSerializer.DeserializeAsync|
Next code block is showing
Startup.cs configurations and a
HomeController.cs code showing how this typed client can be consumed.
|public class Startup|
|public void ConfigureServices(IServiceCollection services)|
|// Use GitHubApiConsumer as key to the configurations|
|c.BaseAddress = new Uri("https://api.github.com/");|
|// Github API versioning|
|// Github requires a user-agent|
|c.DefaultRequestHeaders.Add("User-Agent", "theCodeBlogger.com Demo");|
|public void Configure(IApplicationBuilder app, IWebHostEnvironment env)|
|// Request Pipeline…|
|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;|
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.