I've read a good deal about how HttpClient instances should be reused as much as possible, perhaps even throughout application lifecycle. For completeness sake, here are a couple of the resources that I'm basing my statements on:
- Do HttpClient and HttpClientHandler have to be disposed?
- You're Using HttpClient Wrong and it is Destabilizing Your Software
- What is the overhead of creating a new HttpClient per call in a WebAPI client?
I have a couple of questions regarding this:
- How do I create an application-scoped instance of HttpClient in ASP.NET MVC to be shared among all requests? Let's assume there is no IoC container in picture, so I can't just bind it in Singleton scope with container-name-here and call it a day. How would I do it "manually?"
- Also, the web service I'm interacting with requires a new authorization token on each request, so even if come up with a way to do #1 above, how do I supply a new authorization header on every request, so that it doesn't collide with potential multiple concurrent requests (coming from different users and whatnot)? My understanding is that HttpClient is fairly thread-safe itself, when it comes to GetAsync and other methods, but setting DefaultAuthorizationHeaders doesn't seem thread-safe to me, is it?
- How do I keep it unit-testable?
This is how my in-progress code looks like so far (in a somewhat simplified form for brevity here):
public class MyHttpClientWrapper : IDisposable
{
private readonly HttpClient _httpClient;
private readonly TokenManager _tokenManager;
public HttpServiceClient(HttpClient httpClient, TokenManager tokenManager)
{
_httpClient = httpClient;
_tokenManager = tokenManager;
_httpClient.BaseAddress = new Uri("https://someapp/api/");
_httpClient.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
}
public string GetDataByQuery(string query)
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"amx", _tokenManager.GetNewAuthorizationCode());
var response = _httpClient.GetAsync(query).Result;
return response.Content.ReadAsStringAsync().Result;
}
public void Dispose()
{
HttpClient?.Dispose();
}
}
Side note: I am using dependency injection here, but not necessarily an IoC container (for the reasons irrelevant to this discussion).