Introduction
There are many use cases when one API or backend application (C# console-based application) needs to talk with any other API, then it is very important to understand the way we are making connections to other servers or API to get data.
Improper use of HTTP connections will lead to performance issues and will degrade the performance.
In my last article, I tried to explain the issue with HTTP clients.
We should be careful when opening the connection with the C# code.
If we open and close the http connection each and every time we request, then it will cause performance issues, as explained in the article below.
There are three main symptoms of connection pool starvation.
- Timeouts in the form of TaskCanceledException
- Latency spikes under load
- Low throughput
IHttpClientFactory in .NET Core
When we make an HTTP connection using IHttpClientFactory, we use the concept of connection pooling.
This means each and every time when we need an HTTP client object, we will get an already-created object from the pool and use it.
The cost of creating httpclient will not be there as we are taking the HTTP client object from the pool itself.
The IHttpClientFactory serves as a factory abstraction that can create HttpClient instances with custom configurations.
Understanding above diagram
- IHttptpClientFactory Injected to Clientservice
- Inside the service, when we need an HTTP client object, we will get it from the pool.
- IHttpClientFactory assigns an HttpMessageHandler from a pool to the HttpClient.
- 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.
- We can configure the lifetime of HTTP client objects and also.
Benefits of IHttptpClientFactory
- Resource Management: We can reuse http objects from the pool, which helps in performance improvement
- Configuration and Policies: Using a Named client, we can configure multiple HTTP client objects with different configurations of the named client, which we will discuss later in this article.
- Integration with Polly: Integration with other third-party libraries to make API resilient
We can use Polly to apply circuit breaker patterns, etc.
Lifetime Management
We can manage the lifetime for httpclient objects.
The HttpMessageHandler objects in the pool have a lifetime, which is the length of time that an HttpMessageHandler instance in the pool can be reused. The default value is two minutes, but it can be overridden per Typed Client. To override it, call SetHandlerLifetime() on the IHttpClientBuilder that's returned when creating the client, as shown in the following code.
builder.Services.AddHttpClient<productService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
There are several ways IHttpClientFactory can be used in an app.
Basic Usage
- We need to inject IHttpClientFactory via DI.
builder.Services.AddHttpClient();
- We need to create a client from IHttpClientFactory. We need to use the code below in the controller.
using HttpClient client = _iHttpClientFactory.CreateClient();
var response = await client.GetAsync("http://google.com");
Here, We will get an object from the object pool.
Controller class
Named client
We can use named clients when
In the application, we may need multiple HTTP client objects with different pre-setup configurations.
Example: In an e-commerce application, we need to talk to customer API and order API. Then, we may need to send different headers in both cases, and we can achieve this using a named client.
Program.cs
Controller
Here, we have multiple named clients like order service and customer service.
We can configure settings at startup.cs and can use them in various parts of the application as per the requirement.
Typed client
This Allows you to encapsulate HTTP client configuration and logic in a strongly typed class.
We can directly use the HTTP client in the constructor.
This can be particularly useful for consuming third-party APIs, microservices, or any HTTP-based service in a structured and maintainable way.
We can create custom classes like the ones below.
Service Code