Managing HttpClient Lifetime
Improper HttpClient usage can cause issues:
| Problem | Cause |
|---|---|
| Socket exhaustion | Creating many short-lived clients |
| Stale DNS | Single long-lived client without connection recycling |
✅ Recommended Approaches
Option 1: Long-lived Client with Connection Recycling
Create one client and set PooledConnectionLifetime:
var handler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(15)
};
var sharedClient = new HttpClient(handler);
Warning
SocketsHttpHandler is only available in .NET Core 2.1+ and .NET 5+. Not available for .NET Framework.
Note
Don't dispose this client—it's designed to live for the entire application lifetime.
Adding Polly Resilience
using Microsoft.Extensions.Http.Resilience;
using Polly;
var resiliencePipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddTimeout(Gw2Resiliency.TotalTimeoutStrategy)
.AddRetry(Gw2Resiliency.RetryStrategy)
.AddCircuitBreaker(Gw2Resiliency.CircuitBreakerStrategy)
.AddHedging(Gw2Resiliency.HedgingStrategy)
.AddTimeout(Gw2Resiliency.AttemptTimeoutStrategy)
.Build();
var primaryHandler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(15)
};
var resilienceHandler = new ResilienceHandler(resiliencePipeline)
{
InnerHandler = primaryHandler,
};
var httpClient = new HttpClient(resilienceHandler);
See Resilience with static clients for more details.
Option 2: IHttpClientFactory
Let the factory manage connection lifetimes. Disposing the HttpClient returns connections to the pool.
using System.Drawing;
using GuildWars2;
using GuildWars2.Hero.Equipment.Dyes;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Pastel;
HostApplicationBuilder appBuilder = Host.CreateApplicationBuilder(args);
// Set up the HTTP client factory
appBuilder.Services.AddHttpClient<Gw2Client>();
// Configure logging
appBuilder.Logging.AddSimpleConsole(options =>
{
options.ColorBehavior = LoggerColorBehavior.Enabled;
options.SingleLine = true;
}
);
IHost app = appBuilder.Build();
// Obtain a Gw2Client from the service provider, which uses the HTTP client factory
Gw2Client gw2 = app.Services.GetRequiredService<Gw2Client>();
// Some demo code to print dye colors, using Pastel to colorize the console output
foreach (DyeColor dye in await gw2.Hero.Equipment.Dyes.GetColors().ValueOnly().ConfigureAwait(false))
{
PrintColor(dye.Name, dye.Cloth.Rgb, dye.Leather.Rgb, dye.Metal.Rgb);
}
// Helper method to print a row of colors
void PrintColor(string name, Color cloth, Color leather, Color metal)
{
app.Services.GetRequiredService<ILogger<DyeColor>>()
.LogInformation(
"{Name,-20} {Cloth,-25} {Leather,-25} {Metal,-25}",
name,
" C ".Pastel(Invert(cloth)).PastelBg(cloth),
" L ".Pastel(Invert(leather)).PastelBg(leather),
" M ".Pastel(Invert(metal)).PastelBg(metal)
);
static Color Invert(Color color)
{
return Color.FromArgb(color.ToArgb() ^ 0xffffff);
}
}
📚 Additional Resources
| Resource | Description |
|---|---|
| HttpClient Guidelines | Microsoft's official best practices |
| IHttpClientFactory with .NET | Factory pattern deep dive |
Guidance for ASP.NET Core applications: