Experimenting with HttpClient
Hello! I this post I’ll try to share with you my experience working with the HttpClient
class in c#.
But let’s start from the beginning, what is HttpClient
? We can find this class under System.Net.Http
namespace and it is an abstraction to handle easily Http communications.
Provides a class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI.
Great! Now we have a tool to consume REST APIs in an easy way. Take a look at the following example. We can consume a public API to get some details from “Star Wars” characters.
As we can see, in that code fragment, we are using the HttpClient
to get the details for the character 1. In response, we are getting some info about “Luke Skywalker”.
But this implementation has an issue, we are creating a new HttpClient
instance each time that GetStarWarsCharacter
method is being invoked. And why that is bad if HttpClient
implements IDisposable
?
The issue is not with the pattern implementation itself. When we create a new HttpClient
instance, this one creates a new socket internally in order to establish the communication. Since an app can have access to a limited amount of sockets, being creating new instances can lead to socket starvation issues.
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.
So, how we should instantiate it?? In order to avoid this kind of issue, we have a couple of techniques. Let’s review some of them:
Static approach
Declaring the HttpClient
as static
allows us to instantiate the client only one time across all the app.
IHttpClientFactory to the rescue
Since NET Core 2.1, we can make use of the DefaultHttpClientFactory
class, which implements the IHttpClientFactory
interface. This will allows us to create new HttpClient
instances.
In order to inject it properly, we should register it making use of the AddHttpClient()
extension method.
According to Microsoft, the use of the factory has the following advantages:
The current implementation of IHttpClientFactory, that also implements IHttpMessageHandlerFactory, offers the following benefits:
Provides a central location for naming and configuring logical
HttpClient
objects. For example, you may configure a client (Service Agent) that's pre-configured to access a specific microservice.Codify the concept of outgoing middleware via delegating handlers in
HttpClient
and implementing Polly-based middleware to take advantage of Polly's policies for resiliency.
HttpClient
already has the concept of delegating handlers that could be linked together for outgoing HTTP requests. You can register HTTP clients into the factory and you can use a Polly handler to use Polly policies for Retry, CircuitBreakers, and so on.Manage the lifetime of HttpMessageHandler to avoid the mentioned problems/issues that can occur when managing
HttpClient
lifetimes yourself.
This means that now we have the ability to configure the client in a centralized way in order to be re-used later. Let’s see some approaches:
Named client
In this, case we registered a client with the “StarWars” name, where we set the BaseAddress
. Then, in the controller, we are creating a new client instance based on the name that we defined previously.
As we can see, we don’t need to define the complete URL in the controller since we already did it in the registration, we only need to set the resource we want to get.
Typed clients
As per Microsoft definition:
It’s just an
HttpClient
that's pre-configured for some specific use. This configuration can include specific values such as the base server, HTTP headers or time outs.
For this scenario, I created a new class library project in order to have centralized the client in only one place. The first thing I did is to create a new class: “StarWarsApiClient”, from this class I’ll manage all the communication between the public API.
Then we should register this client, to achieve this, I created an extension class.
Now, we only need to invoke it.
But there is more, we can add our own message handlers.
A message handler is a class that receives an HTTP request and returns an HTTP response. Message handlers derive from the abstract HttpMessageHandler class.
Typically, a series of message handlers are chained together. The first handler receives an HTTP request, does some processing, and gives the request to the next handler. At some point, the response is created and goes back up the chain. This pattern is called a delegating handler.
Each time you get an HttpClient
object from the IHttpClientFactory
, a new instance is returned. But each HttpClient
uses an HttpMessageHandler
that's pooled and reused by the IHttpClientFactory
to reduce resource consumption, as long as the HttpMessageHandler
's lifetime hasn't expired.
With all this in mind, now we have the tools to work with APIs using good practices and avoiding some common mistakes.
If you want, you can check the code here.
Enjoy and happy coding! : )