What Is the Overhead of Creating a New Httpclient Per Call in a Webapi Client

What is the overhead of creating a new HttpClient per call in a WebAPI client?

HttpClient has been designed to be re-used for multiple calls. Even across multiple threads.
The HttpClientHandler has Credentials and Cookies that are intended to be re-used across calls. Having a new HttpClient instance requires re-setting up all of that stuff.
Also, the DefaultRequestHeaders property contains properties that are intended for multiple calls. Having to reset those values on each request defeats the point.

Another major benefit of HttpClient is the ability to add HttpMessageHandlers into the request/response pipeline to apply cross cutting concerns. These could be for logging, auditing, throttling, redirect handling, offline handling, capturing metrics. All sorts of different things. If a new HttpClient is created on each request, then all of these message handlers need to be setup on each request and somehow any application level state that is shared between requests for these handlers also needs to be provided.

The more you use the features of HttpClient, the more you will see that reusing an existing instance makes sense.

However, the biggest issue, in my opinion is that when a HttpClient class is disposed, it disposes HttpClientHandler, which then forcibly closes the TCP/IP connection in the pool of connections that is managed by ServicePointManager. This means that each request with a new HttpClient requires re-establishing a new TCP/IP connection.

From my tests, using plain HTTP on a LAN, the performance hit is fairly negligible. I suspect this is because there is an underlying TCP keepalive that is holding the connection open even when HttpClientHandler tries to close it.

On requests that go over the internet, I have seen a different story. I have seen a 40% performance hit due to having to re-open the request every time.

I suspect the hit on a HTTPS connection would be even worse.

My advice is to keep an instance of HttpClient for the lifetime of your application for each distinct API that you connect to.

Singleton httpclient vs creating new httpclient request

Update: It seems that using a single static instance of HttpClient doesn't respect DNS changes, so the solution is to use HttpClientFactory. See here for Microsoft docs about it.

To use the HttpClientFactory you have to use Microsoft's dependency injection. This is the default for ASP.NET Core projects, but for others you will have to reference Microsoft.Extensions.Http and Microsoft.Extensions.DependencyInjection.

Then when you're creating your service container, you simply call AddHttpClient():

var services = new ServiceCollection();
services.AddHttpClient()
var serviceProvider = services.BuildServiceProvider();

And then you can inject IHttpClientFactory into your services, and behind the scenes HttpClientFactory will maintain a pool of HttpClientHandler objects - keeping your DNS fresh and preventing problems with connection pool exhaustion.


Old answer:

Singleton is the correct way to use HttpClient. Please see this article for full details.

Microsoft docs state:

HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.

And indeed, we found this in our application. We have code that can potentially make hundreds of API requests in a foreach loop, and for each iteration we were creating an HttpClient wrapped in a using. We soon started getting red herring errors from our MongoClient saying that it had timed out trying to connect to the database. After reading the linked article, we found that even after disposing of HttpClient, and realised that we were exhausting the available sockets.

The only thing to note is that things like DefaultRequestHeaders and BaseAddress will be applied anywhere that HttpClient is used. As a singleton, this is potentially throughout the application. You can still create multiple HttpClient instances in your application, but just be aware that each time you do, they create a new connection pool and, as such, should be created sparingly.

As pointed out by hvaughan3, you also can't change the instance of HttpMessageHandler used by the HttpClient, so if this matters to you, you would need to use a separate instance with that handler.

Should I use one HttpClient instance per request or one to handle all my requests?

You should try to reuse HttpClient instances as much as possible. The only reason to create a new instance is if you want to configure it differently.

Should I create new HttpClient for each new request?

I had an answer to a similar question that may help. I basically use:

// Should be thread safe
public class HttpClientFactory {

private static DefaultHttpClient client;

public synchronized static DefaultHttpClient getThreadSafeClient() {
if (client != null)
return client;
client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
mgr.getSchemeRegistry()), params);
return client;

}
}

The question has the full posting.

C# efficient use of HttpClient

A static HttpClient (or an instance field on a singleton, which is essentially the same thing) is the proper way to go for modern versions of .NET Core. The SocketsHttpHandler in .NET Core 2.1 and newer handles the DNS problems inherent in the singleton HttpClient approach.

Reuse or create new Windows.Web.Http.HttpClient

Reuse or create new Windows.Web.Http.HttpClient

The short answer yes, it could be reused. We often make single-instance pattern to package HttpClient. You could keep an instance of HttpClient for the lifetime of your application for each distinct API. And the following is thread safe.

public class HttClientProvider
{
private static HttpClient _instance = null;
private static readonly object _instanceLock = new object();
public static HttpClient Instance
{
get
{
if (null == _instance)
{
lock (_instanceLock)
{
if (null == _instance)
{
_instance = new HttpClient();
}
}
}
return _instance;
}
}
}


Related Topics



Leave a reply



Submit