← Back to Articles         
IHttpClientFactory for Microservices

IHttpClientFactory for Microservices

Published on 28 Sep 2026     7 min read Microservices
Microservice Design

Why Should You Use IHttpClientFactory for Service-to-Service Communication?

1. What is IHttpClientFactory?

IHttpClientFactory is ASP.NET Core's built-in mechanism for creating and configuring HttpClient instances.

In microservices, one service often calls another:

Order Service
     │
     │ HTTP Request
     ▼
Product Service

Instead of manually creating HttpClient objects everywhere:

var client = new HttpClient();

you configure clients through ASP.NET Core:

builder.Services.AddHttpClient<ProductApiClient>(client =>
{
    client.BaseAddress = new Uri("https://product-service/");
});

ASP.NET Core then injects the configured HttpClient:

public class ProductApiClient
{
    private readonly HttpClient _httpClient;

    public ProductApiClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
}

2. Why Do We Need IHttpClientFactory?

HttpClient looks simple, but its underlying network connections are managed through HTTP handlers and connection pools.

Poor HttpClient lifetime management can cause problems such as:

  • Connection/socket exhaustion
  • Stale DNS information
  • Duplicated configuration
  • Difficult resilience configuration
  • Difficult logging and monitoring

IHttpClientFactory provides a standardized way to manage these concerns.


3. Problem: Creating HttpClient Repeatedly

Avoid patterns like:

public async Task GetProduct()
{
    using var client = new HttpClient();

    var response = await client.GetAsync(
        "https://product-service/api/products/10");
}

If this pattern is repeatedly executed under load, you're also repeatedly creating handlers/connections rather than efficiently reusing the underlying infrastructure.

Request 1 → New HttpClient
Request 2 → New HttpClient
Request 3 → New HttpClient
Request 4 → New HttpClient
             ↓
      Inefficient connection handling

This can contribute to port/socket exhaustion, particularly under high request volume.


4. How IHttpClientFactory Helps

When you use:

builder.Services.AddHttpClient<ProductApiClient>();

ASP.NET Core manages the underlying handlers separately from the short-lived HttpClient objects.

Conceptually:

ProductApiClient
       │
       ▼
IHttpClientFactory
       │
       ▼
HttpClient
       │
       ▼
Managed/Pooled Handler
       │
       ▼
Product Service

This enables efficient reuse of underlying connections.


5. Handles DNS Changes Better

This is particularly important in distributed environments.

Suppose Product Service originally resolves to:

product-service
      ↓
10.0.0.10

After redeployment or infrastructure changes:

product-service
      ↓
10.0.0.25

Long-lived handlers can potentially continue using stale connection information depending on their configuration.

IHttpClientFactory manages handler lifetimes, allowing handlers and their connection pools to be periodically replaced.

This helps applications adapt to DNS/network changes.


6. Centralized Configuration

Without IHttpClientFactory, configuration can become scattered:

var client = new HttpClient();

client.BaseAddress = ...;
client.Timeout = ...;
client.DefaultRequestHeaders.Add(...);

and the same code may appear in many places.

With IHttpClientFactory:

builder.Services.AddHttpClient<ProductApiClient>(client =>
{
    client.BaseAddress =
        new Uri("https://product-service/");

    client.Timeout =
        TimeSpan.FromSeconds(10);
});

Now Product Service communication is configured in one place.


7. Supports Typed Clients

For microservices, I generally recommend typed clients when a service has a clear external dependency.

For example:

public class ProductApiClient
{
    private readonly HttpClient _client;

    public ProductApiClient(HttpClient client)
    {
        _client = client;
    }

    public async Task<ProductDto?> GetProductAsync(int id)
    {
        return await _client
            .GetFromJsonAsync<ProductDto>(
                $"api/products/{id}");
    }
}

Registration:

builder.Services.AddHttpClient<ProductApiClient>(client =>
{
    client.BaseAddress =
        new Uri("https://product-service/");
});

Then Order Service doesn't need to know the HTTP implementation details:

var product =
    await _productApiClient.GetProductAsync(productId);

This gives a clean separation:

OrdersController
       ↓
ProductApiClient
       ↓
HttpClient
       ↓
Product Microservice

8. Supports Named Clients

You can also configure multiple named clients.

builder.Services.AddHttpClient("ProductService", client =>
{
    client.BaseAddress =
        new Uri("https://product-service/");
});

builder.Services.AddHttpClient("PaymentService", client =>
{
    client.BaseAddress =
        new Uri("https://payment-service/");
});

Then:

public class OrderService
{
    private readonly IHttpClientFactory _factory;

    public OrderService(IHttpClientFactory factory)
    {
        _factory = factory;
    }

    public async Task GetProduct()
    {
        var client =
            _factory.CreateClient("ProductService");

        var response =
            await client.GetAsync("api/products/10");
    }
}

This is useful when your application communicates with several external services.


9. Supports Resilience

Network calls can fail.

Order Service
      │
      X
Product Service

Possible causes include:

  • Temporary network failure
  • Service unavailable
  • Timeout
  • Server overload
  • Connection failure

Modern .NET applications can configure resilience around HttpClient, including strategies such as:

Timeout
Retry
Circuit Breaker
Rate Limiting

Conceptually:

Order Service
      │
      ▼
HttpClient
      │
      ▼
Resilience Pipeline
      │
      ▼
Product Service

This is particularly important in microservices because network calls should always be treated as potentially unreliable.

Retries must be used carefully for operations with side effects, such as payments or order creation.


10. Built-In Logging Integration

IHttpClientFactory integrates with ASP.NET Core logging.

This makes it easier to observe outbound HTTP communication, including information around:

Order Service
      │
      │ HTTP Request
      ▼
Product Service
      │
      │ HTTP Response
      ▼
Order Service

For production microservices, this can be combined with distributed tracing and correlation information to troubleshoot service-to-service calls.


11. Dependency Injection Support

IHttpClientFactory integrates naturally with ASP.NET Core DI.

Registration:

builder.Services.AddHttpClient<ProductApiClient>();

Usage:

public OrdersController(
    ProductApiClient productApiClient)
{
    _productApiClient = productApiClient;
}

ASP.NET Core handles creation and injection.

You don't manually manage the client lifecycle.


12. Advantages

Proper Connection Management

Underlying handlers and connections can be reused efficiently.

Helps Avoid Socket Exhaustion

It avoids the problematic pattern of constantly creating new handlers/connections for every operation.

Better DNS Handling

Handler lifetime management helps applications adapt when network endpoints change.

Centralized Configuration

Configure:

  • Base address
  • Timeout
  • Headers
  • Authentication handlers
  • Resilience

in one place.

DI Integration

Works naturally with ASP.NET Core Dependency Injection.

Named and Typed Clients

Supports clean organization when communicating with multiple services.

Resilience Integration

Provides a natural place to configure timeout, retry and circuit-breaker strategies.

Logging

Integrates with ASP.NET Core's logging infrastructure.


13. Disadvantages

IHttpClientFactory itself adds some concepts and configuration that developers need to understand.

Potential disadvantages include:

  • More setup than simply calling new HttpClient()
  • Incorrect retry policies can create duplicate operations
  • Handler lifetime behavior needs to be understood for advanced scenarios
  • Typed/named clients can become excessive if poorly organized

However, for substantial ASP.NET Core applications making outbound HTTP calls, these trade-offs are usually manageable.


14. new HttpClient() vs IHttpClientFactory

new HttpClient() repeatedly IHttpClientFactory
Manual management Framework-managed creation
Easy to misuse connection lifecycle Handler pooling/lifetime management
Configuration may be scattered Centralized configuration
DNS handling requires care Handler lifecycle helps with DNS changes
Resilience setup can be scattered Central resilience configuration
Manual organization Named/typed clients
Less integrated DI and logging integration

A single properly managed long-lived HttpClient can also be valid. The main problem is creating and disposing clients/handlers repeatedly without understanding connection pooling.


15. Key Points

  • IHttpClientFactory is the standard ASP.NET Core mechanism for configuring and creating HttpClient.
  • It helps manage HTTP handler lifetimes and connection pooling.
  • It helps prevent problems caused by repeatedly creating/discarding HTTP connections.
  • It provides better handling for changing network/DNS environments.
  • It supports named clients and typed clients.
  • Typed clients are especially useful for service-to-service communication.
  • It integrates with Dependency Injection and logging.
  • It provides a convenient foundation for timeouts, retries and circuit breakers.
  • Don't blindly retry non-idempotent operations such as payments.
  • Avoid creating new HttpClient() for every service request.

16. Interview Questions & Answers

Q1. Why should we use IHttpClientFactory?

Answer:
IHttpClientFactory provides centralized HttpClient configuration, manages HTTP handler lifetimes and connection pooling, helps with DNS changes, and integrates with dependency injection, logging, and resilience mechanisms.

Q2. What problem does it solve?

Answer:
It helps avoid common HttpClient lifetime problems, especially inefficient connection management and socket/port exhaustion caused by repeatedly creating and disposing HTTP handlers.

Q3. Does IHttpClientFactory reuse the same HttpClient object?

Answer:
Not necessarily. HttpClient instances can be short-lived. The important part is that IHttpClientFactory pools and manages the underlying HttpMessageHandler instances, which manage connection pools.

Q4. What is a typed client?

Answer:
A typed client is a class that encapsulates all HTTP communication with a specific external service.

Order Service
      ↓
ProductApiClient
      ↓
HttpClient
      ↓
Product Service

Q5. Named client vs typed client?

Answer:
A named client is retrieved by a configured name, while a typed client wraps HttpClient inside a strongly typed service class. Typed clients often provide cleaner service-specific APIs.

Q6. Does IHttpClientFactory support retry and circuit breaker?

Answer:
Yes. ASP.NET Core/.NET HTTP clients can be integrated with resilience pipelines to provide strategies such as retry, timeout, and circuit breaker.

Interview One-Line Answer

Use IHttpClientFactory because it provides safe and centralized HttpClient management, handler/connection pooling, better DNS handling, DI and logging integration, and a clean foundation for resilient service-to-service HTTP communication.

← Back to Articles