Reuse HttpClient instead of creating one per request. In .NET Core and .NET 5 and later, use a static or singleton client with PooledConnectionLifetime set, or short lived clients from IHttpClientFactory. Per request clients waste connections, can exhaust ports, and a never recycled client can keep calling an old address after DNS changes.
Why lifetime is a reliability and security topic
Each HttpClient has its own connection pool, which isolates its requests from others. Microsoft's guidelines explain two failure modes.
- Port exhaustion. TCP ports are not released immediately when a connection closes, because of the TIME-WAIT state. If a service creates and disposes clients at a high rate, the operating system limit of available ports can run out. The advice is to reuse instances for as many requests as possible.
- Stale DNS. HttpClient resolves DNS only when it creates a connection and does not track DNS time to live. If addresses change, a long lived connection keeps going to the old one. This matters for failover, blue green deployments and moving a dependency to a new address.
Outages that look like random timeouts under load often trace back to these two.
The two supported patterns
| Pattern | When to use | Key setting |
|---|---|---|
| Static or singleton client | One or a few clients with fixed configuration | SocketsHttpHandler.PooledConnectionLifetime |
| IHttpClientFactory | Many differently configured clients, typed clients | Handler lifetime, managed by the factory |
For the first pattern the documentation shows a handler with PooledConnectionLifetime of 15 minutes, noting that the interval was chosen for illustration and should reflect how often DNS or network changes occur. Elsewhere in the same page it mentions a value such as 2 minutes. Choose from your own environment.
var handler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2)
};
var client = new HttpClient(handler);
The factory pools handlers and reuses them while their lifetime has not expired, which avoids socket exhaustion. The docs recommend typed clients when you want the factory's configuration features.
A cookie caveat
The guidelines warn that if your app needs cookies, avoid IHttpClientFactory. Pooling handlers means sharing CookieContainer objects, and unanticipated sharing can leak cookies between unrelated parts of the application. When a handler is recycled, its stored cookies are lost.
Security settings that belong on the handler
Set these where you build the handler, once:
- A timeout. See the post on the HttpClient default timeout.
- Automatic redirect limits for calls to user supplied URLs.
- Certificate validation left at its secure default. Do not assign a callback that always returns true.
- Credentials attached per request or through a delegating handler, not in a shared default header, when one client talks to several hosts.
Steps
- Search for new HttpClient inside methods and using statements.
- Replace them with one shared client or typed clients from the factory.
- Set PooledConnectionLifetime on the shared handler.
- Avoid the factory if the app depends on cookies.
- Check the process for TIME-WAIT build up during a load test.
- Test a DNS change in staging and confirm the client follows it.
Quick check
Is it wrong to dispose an HttpClient?
Disposing disposes the pool only when the client owns the handler. The problem is doing it on every request. Long lived reuse is the aim.
Does the factory fix DNS staleness?
It recycles handlers on a lifetime, which bounds how long a connection can live. You still choose the lifetime.
Safeguard dependency scanning and SBOM generation cover the NuGet packages your service uses, and the free scan is at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.