Experimenting with HttpClient

Matias Paulo
5 min readJul 27, 2021

--

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 HttpClientto 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 HttpClientinstance, 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

Startup.cs
StarWarsController.cs

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.

From here we can centralize the client configuration

Now, we only need to invoke it.

The “BaseAddress” can be read it from the “appsettings” file

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! : )

--

--