[C#]How to Correctly Create HttpClient Using IHttpClientFactory in C#

目次

Overview

This implementation pattern uses IHttpClientFactory to solve issues like “socket exhaustion” and “DNS changes not being reflected,” which occur when new HttpClient() is reused incorrectly or disposed of too quickly. You inject the factory through the Dependency Injection (DI) container and create a properly configured HttpClient instance.

Specifications (Input/Output)

  • Input: Web API URL.
  • Output: Result of the API call using a client generated via IHttpClientFactory.
  • Prerequisites: .NET Core 2.1 or higher (recommend .NET 6.0 or higher). Requires the Microsoft.Extensions.Http package.

Basic Usage

You need to register the service in the DI container and then inject it into your class.

Registration (Startup.cs / Program.cs):

services.AddHttpClient();

Usage in a class:

public class MyService 
{ 
    private readonly IHttpClientFactory _factory; 
    
    public MyService(IHttpClientFactory factory) 
    { 
        _factory = factory; 
    } 
    
    public async Task DoWork() 
    { 
        // Create the client here
        var client = _factory.CreateClient(); 
        var response = await client.GetAsync("..."); 
    } 
}

Full Code Example

Below is a complete example for a console application where we manually set up the ServiceCollection (DI container) to use IHttpClientFactory.

Required Packages:

Bash

dotnet add package Microsoft.Extensions.Http
dotnet add package Microsoft.Extensions.DependencyInjection
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; // For DI

class Program
{
    static async Task Main()
    {
        // 1. Setup DI container
        var services = new ServiceCollection();

        // Register HttpClient features (AddHttpClient)
        services.AddHttpClient();

        // Register the worker class that uses HttpClient
        services.AddTransient<MyWorker>();

        // Create provider
        var serviceProvider = services.BuildServiceProvider();

        // 2. Get and execute the worker class
        var worker = serviceProvider.GetRequiredService<MyWorker>();
        
        try
        {
            await worker.RunAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

// Class that performs HTTP communication
public class MyWorker
{
    private readonly IHttpClientFactory _clientFactory;

    // Receive the factory via constructor injection
    public MyWorker(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public async Task RunAsync()
    {
        // 3. Create HttpClient from the factory
        // The lifecycle of the internal handler is managed automatically
        var client = _clientFactory.CreateClient();

        string url = "http://httpbin.org/get";
        Console.WriteLine($"Accessing: {url}");

        // Use it as usual
        string result = await client.GetStringAsync(url);
        
        Console.WriteLine("--- Result ---");
        // Display part of the result
        Console.WriteLine(result.Substring(0, Math.Min(result.Length, 200)));
    }
}

Customization Options

  • Named Clients: Use this when you want to pre-set base URLs or headers for specific APIs.
// During registration
services.AddHttpClient("GitHub", c => {
    c.BaseAddress = new Uri("https://api.github.com/");
    c.DefaultRequestHeaders.Add("User-Agent", "C# App");
});

// During usage
var client = _factory.CreateClient("GitHub");
  • Typed Clients: This is the recommended method. You create a client specifically for a certain class instead of using string names.
services.AddHttpClient<GitHubService>();

Important Notes

  • No Need to Dispose: You generally do not need to dispose of the HttpClient instance created by factory.CreateClient(). While doing so is not harmful, the factory manages the internal resources.
  • Singleton Usage: IHttpClientFactory itself is registered as a singleton. The HttpClient instances it creates are temporary, but the internal message handlers (which manage connections) are pooled and reused for efficient communication.

Advanced Usage

Applying Policies (Retries, etc.)

By using the Microsoft.Extensions.Http.Polly package, you can set up retry logic for failed communications.

// Example: Retry 3 times on timeout or 500 errors
services.AddHttpClient("MyClient")
    .AddTransientHttpErrorPolicy(builder => 
        builder.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));

Conclusion

When performing HTTP communication in .NET Core or later applications, the best practice is to obtain instances through IHttpClientFactory rather than using new HttpClient() directly. This helps avoid network-specific issues like TCP socket exhaustion and missing DNS updates at the framework level. Since registration only requires the AddHttpClient method, it is easy to implement and highly effective.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次