IHttpClientFactory creates HttpClient instances for calling remote HTTP APIs. Register it with dependency injection using builder.Services.AddHttpClient(), then request IHttpClientFactory and call CreateClient(). The factory manages the underlying handlers so you can create clients without managing their connection lifetimes yourself. section 33.2.1
Why not create and dispose an HttpClient for every request? Disposing its handler can leave sockets unavailable temporarily; enough rapid requests can cause socket exhaustion. Keeping one HttpClient for the application avoids that problem but can miss DNS changes. IHttpClientFactory reuses handler pipelines and periodically replaces them, addressing both concerns. section 33.1 section 33.2.1
Listing 33.3 Using IHttpClientFactory to create an HttpClient
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpClient(); #1 WebApplication app = builder.Build(); app.MapGet("/", async (IHttpClientFactory factory) => #2 { HttpClient client = factory.CreateClient(); #3 client.BaseAddress = #4 new Uri("https://example.com/rates/"); #4 var response = await client.GetAsync("latest"); #5 response.EnsureSuccessStatusCode(); #5 return await response.Content.ReadAsStringAsync(); #5 }); app.Run(); #1 Registers the IHttpClientFactory service in DI #2 Injects the IHttpClientFactory using DI #3 Creates an HttpClient instance with an HttpClientHandler managed by the factory #4 Configures the HttpClient for calling the API as before #5 Uses the HttpClient in exactly the same way you would otherwise
The minimal API example shows AddHttpClient() registration, factory injection into an endpoint, and CreateClient() before an outgoing request. section 33.2.1
Choose the client pattern that fits the calling code:
- Use CreateClient() when you want a client and will configure it where it is used. section 33.2
- Use a named client to centralize configuration for a particular API; register it with AddHttpClient("test", c => { ... }) and retrieve it with CreateClient("test"). section 33.5
- Use a typed client to put HTTP calls behind a service. Register it with AddHttpClient<T>(); the service receives a configured HttpClient, while its consumers need not handle the HTTP mechanics. section 33.5
Underneath each client is an outgoing HttpMessageHandler pipeline. Its final HttpClientHandler makes the network request; earlier handlers can adjust requests and inspect responses. For example, a DelegatingHandler can attach an API-key header to every request from a named or typed client. Register the handler with dependency injection, then add it with AddHttpMessageHandler<T>(); registration order determines pipeline order. section 33.2.1 section 33.4
Transient failures need a separate decision: Microsoft.Extensions.Http.Polly can add a retry policy with AddTransientHttpErrorPolicy(). Retries may help with brief network problems, but consider whether a request should fail quickly instead of repeatedly retrying an error that will not clear. section 33.5

