In this post I take a look at the code in the default implementation of IHttpClientFactory in ASP.NET Core—DefaultHttpClientFactory. We’ll see how it ensures that HttpClient instances created with the factory prevent socket exhaustion, while also ensuring that DNS changes are respected.

This post assumes you already have a general idea of _IHttpClientFactory_ and what it’s used for, so if it’s new to you, take a look at Steve Gordon’s series on IHttpClientFactory, or see the docs.

The code in this post is based on the HEAD of the master branch of https://github.com/dotnet/runtime at the time of writing, after .NET 5 preview 7. But the code hasn’t changed significantly for 2 years, so I don’t expect it to change much soon!

I’ve taken a couple of liberties with the code by removing null checks, in-lining some trivial methods, and removing some code that’s tangential to this discussion. For the original code, see GitHub.

A brief overview of IHttpClientFactory

IHttpClientFactory allows you to create HttpClient instances for interacting with HTTP APIs, using best practices to avoid common issues. Before IHttpClientFactory, it was common to fall into one of two traps when creating HttpClient instances:

IHttpClientFactory was added in .NET Core 2.1, and solves this issue by separating the management of HttpClient, from the the HttpMessageHandler chain that is used to send the message. In reality, it is the lifetime of the HttpClientHandler at the end of the pipeline that is the important thing to manage, as this is the handler that actually makes the connection

HttpClient and HttpClientHandler pipeline

In addition to simply managing the handler lifetimes, IHttpClientFactory also makes it easy to customise the generated HttpClient and message handler pipeline using an IHttpClientBuilder. This allows you to “pre-configure” a named of typed HttpClient that is created using the factory, for example to set the base address or add default headers:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("github", c =>
    {
        c.BaseAddress = new Uri("https://api.github.com/");
    })
    .ConfigureHttpClient(c => 
    {
        c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
        c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
    });
}

#asp.net core #httpclient #dependency injection #source code dive

Exploring the code behind IHttpClientFactory in depth
3.85 GEEK