HttpClient lifecycle, DNS resolution, connection pooling, TLS handshake, request pipeline, response deserialization
You write await httpClient.GetAsync(url) and get a response back.
But what actually happens between those two moments?
This guide walks through every step — from DNS resolution to response deserialisation — explaining the mechanics that make HTTP calls work in .NET.
Step 1: HttpClient and IHttpClientFactory
HttpClient is the entry point for all outgoing HTTP calls in .NET.
The problem with new HttpClient()
// ❌ Never do this in a loop or per-request
using var client = new HttpClient();
Creating a new HttpClient per request:
- Does not reuse TCP connections — expensive
- Exhausts socket connections under load (socket exhaustion)
- Ignores DNS changes (stale DNS)
The solution: IHttpClientFactory
// Register once
builder.Services.AddHttpClient("OrdersApi", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
client.Timeout = TimeSpan.FromSeconds(30);
});
// Inject and use
public class OrderService
{
private readonly HttpClient _client;
public OrderService(IHttpClientFactory factory)
{
_client = factory.CreateClient("OrdersApi");
}
}
IHttpClientFactory manages a pool of HttpMessageHandler instances, reusing connections safely while respecting DNS TTLs.
Step 2: DNS Resolution
Before a TCP connection can be established, the hostname must resolve to an IP address.
api.example.com → 104.21.45.22
- Check the local DNS cache
- If not cached, query the configured DNS server
- DNS server responds with an IP address (and TTL)
- Result is cached for the duration of the TTL
IHttpClientFactory rotates handlers on a schedule (default: 2 minutes) to pick up DNS changes and avoid stale IPs.
Step 3: TCP Connection
With the IP resolved, a TCP connection is established via the 3-way handshake.
Client → SYN → Server
Client ← SYN-ACK ← Server
Client → ACK → Server
(Connection established)
SocketsHttpHandler (the default in .NET 5+) maintains a connection pool per host. Once established, connections are reused for subsequent requests (keep-alive), which dramatically reduces latency under load.
Step 4: TLS Handshake (HTTPS)
For HTTPS, a TLS handshake occurs after TCP.
- Client sends
ClientHellowith supported cipher suites - Server responds with certificate and chosen cipher
- Client verifies the certificate against trusted CAs
- Keys are exchanged; the session is encrypted
TLS session resumption and HTTP/2 multiplexing reduce this overhead on subsequent requests.
Step 5: HTTP Request
With the connection established and encrypted, the HTTP request is sent.
GET /orders HTTP/2
Host: api.example.com
Authorization: Bearer eyJhbGci...
Accept: application/json
HTTP/1.1 vs HTTP/2
HTTP/1.1 sends requests sequentially per connection.
HTTP/2 multiplexes multiple requests over a single connection — significantly more efficient for APIs making many concurrent calls.
var handler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = true
};
Step 6: The Response
The server processes the request and returns a response.
HTTP/2 200 OK
Content-Type: application/json
{ "orders": [...] }
Deserialisation in .NET
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var orders = await response.Content.ReadFromJsonAsync<List<Order>>();
ReadFromJsonAsync uses System.Text.Json — fast, low-allocation JSON deserialisation built into .NET.
Retry Policies with Polly
Real-world APIs fail. Transient failures (timeouts, 503s) should be retried.
builder.Services.AddHttpClient("OrdersApi")
.AddTransientHttpErrorPolicy(policy =>
policy.WaitAndRetryAsync(3, attempt =>
TimeSpan.FromMilliseconds(200 * attempt)));
Polly integrates directly with IHttpClientFactory — retry, circuit breaker, timeout, and fallback policies are all configurable.
Interview-Ready Summary
-
HttpClientshould be created viaIHttpClientFactory— nevernew HttpClient()per request - DNS resolution maps hostname to IP;
IHttpClientFactoryrotates handlers to avoid stale DNS - TCP 3-way handshake establishes the connection
- TLS handshake encrypts the connection (HTTPS)
- HTTP/2 multiplexes multiple requests over one connection
-
ReadFromJsonAsyncdeserialises the response usingSystem.Text.Json - Use Polly for retry policies on transient failures
A strong interview answer:
"Calling an API in .NET goes through DNS resolution, a TCP handshake, a TLS handshake for HTTPS, and then the HTTP request over an established connection. IHttpClientFactory manages connection pooling and handler rotation to avoid socket exhaustion and stale DNS. On the response side, System.Text.Json handles deserialisation. Polly adds retry and circuit breaker policies for resilience."
Top comments (0)