Even though the
IDisposable it is supposed to be used as a singleton as stated in the API reference:
HttpClientis intended to be instantiated once and re-used throughout the life of an application. Instantiating an
HttpClientclass for every request will exhaust the number of sockets available under heavy loads. This will result in
The accepted best practice is to have one
HttpClient per HTTP endpoint you’re interacting with. This will not only yield better performance it also allows to encapsulate endpoint specific logic (such as setting headers).
Now the question is: how do you configure your
IoC container to resolve the expected
HttpClient instance? This used to require a cumbersome registration but
.NET Core 2.1 will ship with the HttpClientFactory making our life much easier.
HttpClientFactory aims to provide the following improvements:
- Alleviate sockets exhaustion by reusing connection when possible
- Alleviate stale
DNSrecords (by default
DNSrecords for its lifetime)
- Easily resolve an
HttpClientinstance linked to a specific HTTP endpoint
What if you can’t use
.NET Core or can’t update? Fear not, we can achieve tomorrow’s dream with today’s tools (most of it anyway).
HttpClient instance with the service using it
HttpClient instances communicating with a specific HTTP endpoint tend to have dedicated settings such as an
Authorization header, default request headers (
Accept for example), maybe a
HMAC… I tend to encapsulate those settings in a
class to decouple the settings’s source from the consummer.
Let’s imagine that we’re integrating with a fictitious company called Contoso. The integration takes place via an HTTP API and our contact at Contoso gave us a bearer token that needs to be set on the
The first step is to create a
POCO modelizing the settings:
HttpClient makes writing tests harder. Developers tend to derive from
HttpMessageHandler and provide an implementation allowing them to assert the requests issued by the
HttpClient. I prefer to introduce an interface called
IHttpClient exposing a single method to handle
We then implement the
ContosoHttpClient that will be dedicated to communicating with the
And finally we registers the
Types in the
This snippet is using
Autofac named service. Using a
named service this way has several benefits:
- If someone registered another
IHttpClientthat is supposed to be used everywhere else we will not override the registration for all the other services while still retrieving an instance of
named serviceis an implementation details that only the
IoCcontainer knows about.
Solve stale DNS records
Let’s say you’re interacting with an API hosted at
HttpClient will first have to resolve the domain name to an
IP thanks to a
DNS server. But what happens if the
DNS record is updated and the domain name now resolves to another
IP? If you are using a transient
HttpClient you’ll be fine but if you’re using a singleton instance (as you should)
Exceptions will start to shoot up in your monitoring system. Should we stop calling APIs, or maybe rewrite everything in
The ConnectionLeaseTimeout property can solve this situation nicely for us:
Int32that specifies the number of milliseconds that an active
ServicePointconnection remains open. The default is
-1, which allows an active
ServicePointconnection to stay connected indefinitely. Set this property to
ServicePointconnections to close after servicing a request.
This is how you set it:
In the previous snippet I’m keeping the connection opened for a minute which seems like a good trade-off.
I haven’t looked at the implementation of
HttpClientFactory yet but I suspect the end result will be fairly similar to what I demonstrated above. If you still have doubts about using a singleton
HttpClient I recommend you to perf test it. At a previous customer I developped an API that was calling other HTTP endpoints, I increased the throughput by a factor of
10 by changing a single thing: I made the
HttpClient a singleton rather than a per-request scope.