We are creating a wrapper for HttpClient. As we are going to follow performance optimization guidance from https://github.com/mspnp/performance-optimization. We want to avoid anti-pattern - Improper instantiation mentioned in that document. I referred this guidance to my team to use static HttpClient. The feedback I have got is on thread-safety. Each request has a header containing user claim. Since I have a static HttpClient, will it be thread-safe? If we have multiple requests hitting the code (for example GET) at the same time, will it be a race condition to set header? We have implementation as below.
public class HttpClientHelper{
private static readonly HttpClient _HttpClient;
static HttpClientHelper() {
HttpClient = new HttpClient();
HttpClient.Timeout = TimeSpan.FromMinutes(SOME_CONFIG_VALUE);
}
public async Task<HttpResponseMessage> CallHttpClientPostAsync(string requestUri, HttpContent requestBody)
{
AddHttpRequestHeader(httpClient);
var response = await httpClient.PostAsync(requestUri, requestBody); //Potential thread synchronization issue???
return response;
}
public HttpResponseMessage CallHttpClientGet(string requestUri)
{
AddHttpRequestHeader(httpClient);
var response = httpClient.GetAsync(requestUri).Result; //Potential thread synchronization issue???
return response;
}
private void AddHttpRequestHeader(HttpClient client)
{
string HeaderName = "CorrelationId";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(Properties.Settings.Default.HttpClientAuthHeaderScheme, GetTokenFromClaims()); //Race condition???
if (client.DefaultRequestHeaders.Contains(HeaderName))
client.DefaultRequestHeaders.Remove(HeaderName);
client.DefaultRequestHeaders.Add(HeaderName, Trace.CorrelationManager.ActivityId.ToString());
}
}
But HttpClient is different. Although it implements the IDisposable interface it is actually a shared object. This means that under the covers it is reentrant and thread safe.
It would be good to add a note that changing BaseAddress or DefaultRequestHeaders is not a thread-safe operation, and you should change them on concurrent requests.
HttpClient is used to send an HTTP request, using a URL. HttpClient can be used to make Web API requests from the console Application, Winform Application, Web form Application, Windows store Application, etc.
The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.
Your team is correct, this is far from thread safe. Consider this scenario:
A better approach would be for your CallXXX methods to create new HttpRequestMessage objects, and set the header on those, and use HttpClient.SendAsync to make the call.
Keep in mind also that re-using HttpClient
instances is only beneficial if you're making multiple calls to the same host.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With