The other day I was building a small demo ASP.NET Core 2.0 application for the purposes of a video course I’m preparing on the upcoming second version of .NET Core.
The application was making several http requests to third party APIs. I noticed that it was taking unusually long to finish. At first I thought that something was wrong with the preview version of .NET Core and curious to find out why I ported it to the stable .NET Core 1.1 and started filling the code with stopwatches to discover the source of the lag.
What I found out was that I have been using the HttpClient all wrong. And probably so do you. All the countless C# books, tutorials and courses out there all mention that the correct usage of the HttpClient is withing a ”using’ statement.
The flow of this thought goes something like this: The HttpClient holds unmanaged resources, it also implement the IDisposable interface. When it comes to other IDisposables like the StreamReader we wrap them in ‘using’ statements so we should do the same with HttpClient.
The problem is, that’s not the case! Creating a new instance of the HttpClient every time we make a request and disposing it after the request completes is not the most sensible thing to do as it turns out. You’re better off having a single HttpClient instance. You can achieve this by creating a wrapper for the HttpClient and either declare it as static or register it as a singleton with your preferred IoC container. The second solution seems more elegant and avoids the static cling code smell.
But let’s take it from the beginning. After the discovering what made my application so slow, I figured I could run a test. So I created a .NET Core Console Applciation from scratch. I then went on to creating two classes, the SlowWay and the FastWay static classes. (I know, awful names). Both classes make several requests to this url: http://jsonplaceholder.typicode.com/photos.
The SlowWay classes follows the famous ‘using’ convention. The FastWay class uses the same HttpClient for all requests
And here’s how I tested them:
With the RequestCount set to 30 I got the following results:
The slow approach takes almost double the time, something that proves my fears about the ‘using’ statement
Increasing the RequestCount to 30 results in almost triple performance decrease:
Increasing to 60 got me even closer to 3 times increase in performance improvement when using the fast approach.
Imagine the performance increase that little modification can lead to in Microservices Oriented Applications.
After digging around the internet for quite some time I stumbled upon an awesome article that describes the source of the issue. Apparently, it’s a TCP socket issue. Check the article from ASP.NET Monsters for more information.
Oh and stop wrapping your HttpClients in ‘using’ statements when making multiple requests. I certainly will.
The whole project is available in this repo: https://github.com/dimlucas/HttpClientPerformanceTest