Full source code here.
There are some subtle issues in the way I use DI in this post, see here for an alternative if you don’t want to follow this approach
While using the HttpClientFactory
I hit a scenario where I needed to update the value of a token passed in the header of requests, the token changed frequently, so I had to repeatedly update it throughout the lifetime of my application.
You have a couple of options for this, the first is to do it after you have taken a HttpClient
from the factory at the point where you make your outbound request, this is straightforward, but now everywhere use a HttpClient
you have to be able to get a new token. For some this might be fine, and you can use –
httpClient.DefaultRequestHeaders.Add("Token", _tokenGenerator.GetToken());
Doing it with HttpClientFactory
The better approach is to put all this logic in the Startup.cs
and update the header when the factory returns a new HttpClient
, now everywhere you use the HttpClient
gets the updated token without any work for you.
In my example case I have a token generator and memory cache. If there is a token in the cache, that one is used, if not the token generator generates and stores the new token in the cache for specified period.
In my Startup.cs
all I need is this –
services.AddHttpClient("RemoteServer", client => { client.BaseAddress = new Uri("http://localhost:5000/api/"); client.DefaultRequestHeaders.Add("Accept", "application/json"); client.DefaultRequestHeaders.Add("Token", TokenGenerator.GetToken()); });
Read on to see how to wire everything up.
A little known feature of .NET Core is the ability to DI from Program.cs
into Startup.cs
, I have written about this before in Using Dependency Injection with Startup.cs in ASP.NET Core and am using it again here.
In Program.cs
I add a memory cache and a token generator to the service collection.
Adding to the service collection this way can have some unexpected side effects, check this post for an alternative approach.
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureServices(cs => cs.AddMemoryCache()) .ConfigureServices(cs => cs.AddSingleton<ITokenGenerator, TokenGenerator>()) .UseStartup<Startup>();
In Startup.cs
I pass a ITokenGenerator
to the constructor.
public Startup(IConfiguration configuration, ITokenGenerator tokenGenerator) { Configuration = configuration; TokenGenerator = tokenGenerator; string token = tokenGenerator.GetToken(); // do something with the token } private ITokenGenerator TokenGenerator { get; } // snip
Then a simple call the TokenGenerator.GetToken()
updates the header of the client the factory returns to callers.
For completeness, here is the implementation of the TokenGenerator.cs
–
public class TokenGenerator : ITokenGenerator { private readonly IMemoryCache _memoryCache; public TokenGenerator(IMemoryCache memoryCache) { _memoryCache = memoryCache; } public string GetToken() { string token; if (_memoryCache.TryGetValue("Token", out token)) { return token; } else { // here you would have a more realistic way of generating a new token token = Guid.NewGuid().ToString(); _memoryCache.Set("Token", token, TimeSpan.FromSeconds(10)); return token; } } }
Full source code here.