DEV Community

Cover image for Why IHttpClientFactory Will Save Your .NET App (and Your TCP Ports!)
Ibrahim Sow
Ibrahim Sow

Posted on

Why IHttpClientFactory Will Save Your .NET App (and Your TCP Ports!)

As .NET developers, we’ve all done this:

var client = new HttpClient();
Enter fullscreen mode Exit fullscreen mode

It’s easy, it works… until your app starts failing unexpectedly due to port exhaustion.
In this article, I’ll explain:

  • Why creating multiple HttpClientinstances is dangerous
  • How IHttpClientFactorysolves the problem
  • How to structure your code using Clean Architecture

❌ The Problem with new HttpClient()

Bad practice: creating HttpClient for every request

public async Task<string> GetWeatherAsync()
{
    using var client = new HttpClient();
    var response = await client.GetAsync("https://api.weather.com/forecast");
    return await response.Content.ReadAsStringAsync();
}
Enter fullscreen mode Exit fullscreen mode

Why is this bad?
Each new HttpClient() opens a fresh TCP connection. When used frequently (e.g., in loops or heavy API calls), this leads to port exhaustion, causing your HTTP requests to fail.

The Right Approach:IHttpClientFactory

.NET introduced IHttpClientFactoryto manage reusable and efficient HttpClientinstances.

Step 1: Define a Service Interface (Clean Architecture)

public interface IWeatherService
{
    Task<string> GetForecastAsync();
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement the Service

public class WeatherService : IWeatherService
{
    private readonly HttpClient _httpClient;

    public WeatherService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> GetForecastAsync()
    {
        var response = await _httpClient.GetAsync("/forecast");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure HttpClient in Program.cs

builder.Services.AddHttpClient<IWeatherService, WeatherService>(client =>
{
    client.BaseAddress = new Uri("https://api.weather.com");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
});
Enter fullscreen mode Exit fullscreen mode

With IHttpClientFactory, .NET reuses connections under the hood, improves performance, and avoids port exhaustion.

What About You?

  • Have you ever experienced port exhaustion in production?
  • Do you prefer Named Clients or Typed Clients with IHttpClientFactory?
  • Let me know in the comments – I’d love to hear your experience!

About Me
I’m a C#/.NET & Angular fullstack developer, passionate about building robust SaaS applications and clean, testable architectures
Contact me on LinkedIn

Top comments (0)