I’ve seen some fierce office arguments about how to use HttpClient in .NET since I’ve been programming. And it’s always about one thing. When exactly do you dispose of an HttpClient instance?

You see there is one train of thought that looks like this :

void DoSomething() { using(HttpClient client = new HttpClient()) { //Do stuff here } }

So you are creating a new instance every time you make an outbound call. Certainly when I first started using the HttpClient class, this seemed logical. But within the past couple of years, this particular article has become pretty infamous : https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/. With the key quotes being :

If we share a single instance of HttpClient then we can reduce the waste of sockets by reusing them

and

In the production scenario I had the number of sockets was averaging around 4000, and at peak would exceed 5000, effectively crushing the available resources on the server, which then caused services to fall over. After implementing the change, the sockets in use dropped from an average of more than 4000 to being consistently less than 400, and usually around 100.

Pretty damning stuff. So in this example, it’s instead favoured to re-use HttpClient instances across the application. And I have to admit, before this article was sent my way, I was definitely in the “always wrap it in a using statement” camp, and that’s generally all I saw out in the wild. These days it’s gone completely the other way, and you would now expect a “static” instance of HttpClient to be created and reused for the lifetime of the application. (There is actually now articles telling you to *not* use a single instance!)

But of course, in comes .NET Core with a new way to manage HttpClient lifetimes, and it’s an interesting one! This guide revolves around using .NET Core 2.1. If you aren’t using version 2.1 yet, there is a handy guide here to get up and running.

HttpClient Factories

Because we are working with .NET Core, and Core has fallen in love with “Dependency Inject all the things”! Then of course Microsoft’s solution for the HttpClient messiness is a DI solution. Let’s imagine that I’m creating an API wrapper for Twitter. So I’m going to create a “TwitterApiClient” class to encapsulate all of this work.

public interface ITwitterApiClient { Task<List<string>> GetTweets(); } public class TwitterApiClient : ITwitterApiClient { public async Task<List<string>> GetTweets() { using (HttpClient client = new HttpClient()) { //Blah blah do everything here I want to do. //var result = await client.GetAsync("/tweets"); return new List<string> { "Tweet tweet" }; } } }

For the sake of brevity, I’m not actually calling out to the Twitter API. But you get the idea that I’ve created a nice wrapper for the API, that has a method called “GetTweets” that would if I wanted to, reach out and get some tweets and return them as a list. Let’s just use our imagination here! You’ll also notice I did this the crap way where we wrap everything in a using statement. This is intentional for now, just to show how things “might have been” before we knew better!

In my ConfigureServices method I’m going to register my TwitterApiClient like so :

services.AddTransient<ITwitterApiClient, TwitterApiClient>();

Now I’m going to go ahead and create a controller that just gets these tweets and writes them on the screen :

[Route("api/[controller]")] public class TweetController : Controller { private readonly ITwitterApiClient _twitterApiClient; public TweetController(ITwitterApiClient twitterApiClient) { _twitterApiClient = twitterApiClient; } [HttpGet] public async Task<IEnumerable<string>> Get() { return await _twitterApiClient.GetTweets(); } }

Run this bad boy and what do we see?

OK so in theory we have everything working, but it’s disposing of our HttpClient each time which as we know from the above article, is a bad idea. So we could create a static instance of HttpClient, but to be perfectly honest, I hate static instances. But we are cutting edge so we are using .NET Core 2.1 (Again if you aren’t yet, you can read our guide to getting up and running with 2.1 here), and now we can use an injected instance of HttpClient. So let’s do that!

First we change our class around. We instead inject in an instance of HttpClient and use this instead.

public class TwitterApiClient : ITwitterApiClient { private readonly HttpClient _client; public TwitterApiClient(HttpClient client) { _client = client; } public async Task<List<string>> GetTweets() { //Blah blah do everything here I want to do. //var result = await _client.GetAsync("/tweets"); return new List<string> { "Tweet tweet" }; } }

Now if you run this at this point, you are gonna see an error close to :

InvalidOperationException: Unable to resolve service for type ‘System.Net.Http.HttpClient’ while attempting to activate […]

This is because Core doesn’t just inject in HttpClient’s by default, there is a tiny bit of configuration needed.

First, we need to install the Microsoft.Extensions.Http nuget package. At the time of writing this is in preview so you will need the full version install command. So from your package manager console it will be something like:

Install-Package Microsoft.Extensions.Http -Version 2.1.0-preview2-final

Now back in our ConfigureServices method in our startup.cs. We are going to add a call to AddHttpClient like so but most importantly, we remove our original call to add a transient instance of our original client. This is super important. I banged my head against a wall for a long time trying to work out what was going wrong with my code. And it turns out when you call AddHttpClient, it actually does a bunch of wiring up for you. If you then call AddTransient yourself, you just overwrite the lot!

public void ConfigureServices(IServiceCollection services) { services.AddHttpClient<ITwitterApiClient, TwitterApiClient>(); //services.AddTransient<ITwitterApiClient, TwitterApiClient>(); services.AddMvc(); }

Give it a run and we should now be all up and running! Now what this code actually does is tell .NET Core to inject in an HttpClient instance into your nice little API wrapper, and it will handle the lifetimes for it. That last part is important. It’s not going to be a singleton, but it’s not going to be a per request type thing either. .NET Core has magic sauce under the hood that means it will at times recycle the underlying connections when it thinks it should.

I’ll admit it’s sort of hazy in a way that Microsoft says “trust us. We’ll sort this for you”. But it’s probably a whole lot better than what you were doing on your own.

Setting Defaults

Taking things a step further, we can actually set up some defaults in our configure method that mean we are configuring our application all in one place (And it’s not hardcoded in our services). As an example, I can do this :

public void ConfigureServices(IServiceCollection services) { services.AddHttpClient<ITwitterApiClient, TwitterApiClient>(client => { client.BaseAddress = new Uri("http://api.twitter.com"); client.Timeout = TimeSpan.FromMinutes(1); }); //services.AddTransient<ITwitterApiClient, TwitterApiClient>(); services.AddMvc(); }

If we decide to read these settings from a config store like appSettings.json, we don’t have to pollute any sort of IOptions throughout our actual Twitter client. Nice!

Named HttpClient Factories

Something else you can do is create named instances of HttpClient that can be created from an HttpClientFactory. This is handy if the class you want to inject HttpClient instances into needs more than one default. So for example a “SocialMediaApiClient” that talks to both Twitter and Facebook.

The setup is slightly different. Instead of saying which class we want to inject our HttpClient into, we just add an instance of HttpClient to the factory with a particular name, and the defaults we want.

public void ConfigureServices(IServiceCollection services) { services.AddHttpClient("twitterClient", client => { client.BaseAddress = new Uri("https://api.twitter.com"); }); services.AddHttpClient("facebookClient", client => { client.BaseAddress = new Uri("https://api.facebook.com"); }); services.AddTransient<ISocialMediaApiClient, SocialMediaApiClient>(); services.AddMvc(); }

Then when it comes to our actual service we first inject an instance of IHttpClientFactory, and then we can get that specific instance of HttpClient by calling CreateClient with the client name as a parameter. Once again, the lifecycle is managed for us as to when it’s disposed of or reused.

public class SocialMediaApiClient : ISocialMediaApiClient { private readonly IHttpClientFactory _httpClientFactory; public SocialMediaApiClient(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public string[] GetTweets() { var client = _httpClientFactory.CreateClient("twitterClient"); Uri endpoint = client.BaseAddress; // Returns https://api.twitter.com ... } }

Generic HttpClient

Finally, the HttpClient factory comes with the ability to generate a new HttpClient on demand which will be managed for you. With this, there shouldn’t ever be a reason to “new up” an instance of HttpClient ever again.

First we just call “AddHttpClient” in our ConfigureServices method, passing in absolutely nothing.

public void ConfigureServices(IServiceCollection services) { services.AddHttpClient(); .... }

And whenever we want to actually get a new instance of an HttpClient. We inject in an instance of IHttpClientFactory and call CreateClient passing in nothing extra.

public void DoSomething() { var client = _httpClientFactory.CreateClient(); }