Last Updated: 27 September 2022

Injecting HttpClient & Using IHttpClientFactory in .Net 6

The problems with the HttpClient surrounding socket exhaustion and DNS updates are well documented. For years, we as developers have known to create a single instance of HttpClient and re-use it throughout the entire application lifetime. This wasn't necessarily the end of it though, but thankfully from .Net Core 2.1 onwards, Microsoft added IHttpClientFactory to configure and handle HttpClient instances. This can be found in the Microsoft.Extensions.Http Nuget Package.

Using this factory has many benefits and are a few different ways to use it. We recommend two of these methods:

  • Inject IHttpClientFactory into class, and call CreateClient() - useful for retrofitting into existing classes
  • Create Typed Clients where a specific pre-configured client is tied to a specific class

Inject IHttpClientFactory

Register the factory in Startup.cs (or wherever you are defining your dependencies) and then add IHttpClientFactory to the constructor of your class. Whenever you need an HttpClient, simply call CreateClient()

Dependency Registration



    public class UsingFactory : IUsingFactory
        private readonly IHttpClientFactory _httpClientFactory;

        public UsingFactory(IHttpClientFactory httpClientFactory)
            _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));

        public void DoSomething()
            var httpClient = _httpClientFactory.CreateClient();

            // use ParkSquare.Extensions.Http methods on httpClient to call API endpoints

Typed Clients

With a typed client, the HttpClient and HttpMessageHandler can be pre-configured just for that particular class. In this example, the class we want the HttpClient injecting into is called TypedClient, which implements the ITypedClient interface. Most of the configuration shown here is optional, to illustrate what can be done. Note the way in which a configuration class (TypedClientConfig) is retrieved from the DI container.

Dependency Registration & HttpClient Configuration

    services.AddSingleton<ITypedClientConfig, TypedClientConfig>();

    services.AddHttpClient<ITypedClient, TypedClient>()
        .ConfigureHttpClient((serviceProvider, httpClient) =>
            var clientConfig = serviceProvider.GetRequiredService<ITypedClientConfig>();
            httpClient.BaseAddress = clientConfig.BaseUrl;
            httpClient.Timeout = TimeSpan.FromSeconds(clientConfig.Timeout);
            httpClient.DefaultRequestHeaders.Add("User-Agent", "BlahAgent");
            httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))    // Default is 2 mins
        .ConfigurePrimaryHttpMessageHandler(x =>
            new HttpClientHandler
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
                UseCookies = false,
                AllowAutoRedirect = false,
                UseDefaultCredentials = true,

Typed Client Implementation

    public class TypedClient : ITypedClient
        private readonly HttpClient _httpClient;

        public TypedClient(HttpClient httpClient)
            _httpClient = httpClient;

        public void DoSomething()
            // Read some properties to prove the intended HttpClient has been injectd in

            Console.WriteLine($"Base address of injected client: {_httpClient.BaseAddress}");
            Console.WriteLine($"Timeout of injected client: {_httpClient.Timeout}");

            // use ParkSquare.Extensions.Http methods on _httpClient to call API endpoints

Configuration Class

    public class TypedClientConfig : ITypedClientConfig
        public TypedClientConfig(IConfiguration configuration)
            if (configuration == null) throw new ArgumentNullException(nameof(configuration));
            configuration.Bind("TypedClient", this);

        public Uri BaseUrl { get; set; }

        public int Timeout { get; set; }


        "TypedClient": {
            "BaseUrl": "",
            "Timeout":  10