Reputation: 381
Since Microsoft recommends that the HttpClient
be created once and reused throughout the life of a program, I wondering how to update DefaultRequestHeaders
when for example, the token has expired and need to be refresh.
DefaultRequestHeaders
is more over not thread safe (for what I know) and the list of headers defined there, shared by all potentially pending requests. Clear()
the list and Add()
the header with a new token, seems not the wise thing to do.
To be more precise, I don't want/need to change request headers for every request. Only when I've got a HTTP 401 status code.
Upvotes: 13
Views: 8286
Reputation: 1537
Wire up a message handler with your HttpClient when you register the IHttpClient in the DI container registry phase or use another pattern such as a factory or singleton to return an instance of the IHttpClient with a custom message handler. Inspect the outbound call and add the necessary headers.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-message-handlers
Sample header message handler
class MessageHandler1 : DelegatingHandler
{
private int _count = 0;
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
System.Threading.Interlocked.Increment(ref _count);
request.Headers.Add("X-Custom-Header", _count.ToString());
return base.SendAsync(request, cancellationToken);
}
}
Sample logger message handler:
class LoggingHandler : DelegatingHandler
{
StreamWriter _writer;
public LoggingHandler(Stream stream)
{
_writer = new StreamWriter(stream);
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode)
{
_writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri,
(int)response.StatusCode, response.Headers.Date);
}
return response;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_writer.Dispose();
}
base.Dispose(disposing);
}
}
Add it to the pipeline
HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());
Threading Concerns
Regarding threading concerns or concurrency, the HttpRequestMessage
parameter on the SendAsync
method will be per request. If you add the header to the request.Headers
collection, you will updating headers for that instance of the request only (i.e., not globally )
Or use the Authorization property on the request.Headers
instance:
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken);
Please see MSDN link below
https://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessage
If you use DefaultRequestHeaders
on a static, shared, singleton, Lifestyle.Singleton, etc, instance of the HttpClient then you will have threading concerns and need proper synchronization to update the DefaultRequestHeaders
collection.
Upvotes: 7