Select Page

Introduction

The release of dotnet core did one step towards platforms compatibility allowing to run the code on Linux as good as on Windows. But one framework does not always mean same behavior between operating systems. HttpClient is one of those things.

Jump directly to solution.

HttpClient cavet

Even though the framework provides same API available on different platforms there are still operating system discrepancies that make same code work slightly different on Linux vs Windows.

A good example of such a difference would be an exception System.IO.IOException: Too many open files that I started getting on my Linux Raspberry PI environment.

Originally written and tested on Windows I let the code running over many hours surfing the Internet and heavily using HttpClient. All went smoothly so that it was time to switch to Raspberry PI as it has lower energy consumption but still sufficient performance for my needs.

Just after an hour running on Raspberry PI the same code started being slowly and finally crashed the process with the numerous exceptions System.IO.IOException: Too many open files left in log files.

This error happens when HttpClient object instantiated directly in your code. HttpClient implements IDisposable so that many developers would correctly assume calling Dispose() method right after HttpClient is not needed anymore.

Unfortunately that won’t fix the problem because of misleading design of HttpClient by dotnet team. The proper fix they recommend is to use a HttpClientFactory. You would basically need to use Dependency Injection to retrieve HttpClient.

Solution

Assuming you have a class ProductService that uses HttpClient. Your code might look like this:

public class ProductService
{
    private readonly HttpClient _httpClient;

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

    // your code below
}

Lastly you’ll just need to register ProductService class in Startup.cs as follows

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<ProductService>();
    
    // your code below
}

That should do the trick and don’t produce the error System.IO.IOException: Too many open files anymore.

Why that happens

Because when an instance of HttpClient is created manually it also implicitly creates an instance of HttpMessageHandler object that occupies sockets. Disposing HttpClient in first place does not cleanup resources properly.

Therefore HttpClientFactory has been introduced. You use it when you call services.AddHttpClient<ProductService>().

That factory has a timer behind the scene disposing HttpMessageHandlers regularly so that the sockets are not occupied anymore.

Why does it say Too many open files when it’s about sockets? Because in Linux the sockets are addressed by file system namespace.

A good description of the problem and solution from Microsoft is available here.

I hope it has helped you to understand and fix the problem if you experience that with dotnet framework.

If you have any questions or suggestions just contact me over the LinkedIn or Twitter.

Take care,
Ievgen