In frequently used code paths, such as controller actions, you should avoid using the HttpClient directly and opt for one of the IHttpClientFactory-based mechanisms instead. This way, you avoid wasting resources and creating performance overhead.

## Why is this an issue?

If a code path that creates and disposes of HttpClient objects is frequently used, then the following issues can occur:

- Under heavy load, there’s the risk of running out of available sockets, leading to SocketException errors. This is because each HttpClient instance uses a separate network connection, and there’s a limit to the number of connections that can be opened simultaneously. Note that even after you dispose of an HttpClient its sockets are not immediately freed up.
- Each HttpClient has its own set of resources (like headers, base address, timeout, etc.) that must be managed. Creating a new HttpClient for every request means these resources are not being reused, leading to resource waste.
- You introduce a significant performance overhead when creating a new HttpClient for every HTTP request.

## How to fix it

The `IHttpClientFactory` was introduced in ASP.NET Core 2.1 to solve these problems. It handles pooling HTTP connections to optimize performance and reliability.

There are several ways that you can use IHttpClientFactory in your application:

- Basic usage
- Named Clients
- Typed Clients
- Generated Clients

Alternatively, you may cache the HttpClient in a singleton or a static field. You should be aware that by default, the HttpClient doesn’t respect the DNS’s Time To Live (TTL) settings. If the IP address associated with a domain name changes, HttpClient might still use the old, cached IP address, leading to failed requests.

### Code examples

#### Noncompliant code example

    [ApiController]
    [Route("controller")]
    public class FooController : Controller
    {
        [HttpGet]
        public async Task<string> Foo()
        {
            using var client = new HttpClient();  // Noncompliant
            return await client.GetStringAsync(_url);
        }
    }

#### Compliant solution

    // File: Startup.cs
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient();
            // ...
        }
    }

    [ApiController]
    [Route("controller")]
    public class FooController : Controller
    {
        private readonly IHttpClientFactory _clientFactory;

        public FooController(IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
        }

        [HttpGet]
        public async Task<string> Foo()
        {
            using var client = _clientFactory.CreateClient(); // Compliant (Basic usage)
            return await client.GetStringAsync(_url);
        }
    }

## Resources

### Documentation

- {rule:csharpsquid:S6420} - Client instances should not be recreated on each Azure Function invocation
- Microsoft Learn - IHttpClientFactory Interface
- Microsoft Learn - HttpClient Class
- Microsoft Learn - IHttpClientFactory with .NET
- Microsoft Learn - Use IHttpClientFactory to implement resilient HTTP requests
- Microsoft Learn - Make HTTP requests using IHttpClientFactory in ASP.NET Core
- Microsoft Learn - Guidelines for using HttpClient