Dynamically Updating the Request Header of a HttpClientFactory Generated HttpClient, Part 1
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 -
1services.AddHttpClient("RemoteServer", client =>
2{
3 client.BaseAddress = new Uri("http://localhost:5000/api/");
4 client.DefaultRequestHeaders.Add("Accept", "application/json");
5 client.DefaultRequestHeaders.Add("Token", TokenGenerator.GetToken());
6});
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.
1public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
2 WebHost.CreateDefaultBuilder(args)
3 .ConfigureServices(cs => cs.AddMemoryCache())
4 .ConfigureServices(cs => cs.AddSingleton<ITokenGenerator, TokenGenerator>())
5 .UseStartup<Startup>();
In Startup.cs
I pass a ITokenGenerator
to the constructor.
1public Startup(IConfiguration configuration, ITokenGenerator tokenGenerator)
2{
3 Configuration = configuration;
4 TokenGenerator = tokenGenerator;
5 string token = tokenGenerator.GetToken(); // do something with the token
6}
7
8private ITokenGenerator TokenGenerator { get; }
9// 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
-
1public class TokenGenerator : ITokenGenerator
2{
3 private readonly IMemoryCache _memoryCache;
4 public TokenGenerator(IMemoryCache memoryCache)
5 {
6 _memoryCache = memoryCache;
7 }
8
9 public string GetToken()
10 {
11 string token;
12 if (_memoryCache.TryGetValue("Token", out token))
13 {
14 return token;
15 }
16 else
17 {
18 // here you would have a more realistic way of generating a new token
19 token = Guid.NewGuid().ToString();
20 _memoryCache.Set("Token", token, TimeSpan.FromSeconds(10));
21
22 return token;
23 }
24 }
25}
Full source code here.