Round-robin DNS is a load-balancing technique in which a DNS server returns multiple IP addresses for a single host, allowing clients to connect to any of them. For example, bing.com resolves to 2 IPv4 addresses:

By default, HttpClient in .NET connects using the first IP address returned by DNS. It only falls back to the next address if the connection fails. When the first address succeeds, every subsequent connection reuses it, which negates the load-balancing benefit of round-robin DNS.
You can customize HttpClient to distribute connections across all available IP addresses. SocketsHttpHandler.ConnectCallback lets you create the TCP connection manually, giving you full control over which address is used.
C#
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
var indexByHosts = new ConcurrentDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
var sockerHttpHandler = new SocketsHttpHandler()
{
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1),
PooledConnectionLifetime = TimeSpan.FromMinutes(1),
ConnectCallback = async (context, cancellationToken) =>
{
// Get the list of IP addresses for the host
// note: AddressFamily.Unspecified: IPv4 or IPv6
var entry = await Dns.GetHostEntryAsync(context.DnsEndPoint.Host, AddressFamily.Unspecified, cancellationToken);
IPAddress[] addresses;
if (entry.AddressList.Length == 1) // No need to handle round-robin as there is only 1 address
{
addresses = entry.AddressList;
}
else
{
// Compute the first IP address to connect to
var index = indexByHosts.AddOrUpdate(
key: entry.HostName,
addValue: Random.Shared.Next(),
updateValueFactory: (host, existingValue) => existingValue + 1);
index %= entry.AddressList.Length;
if (index == 0)
{
// no need to change the addresses
addresses = entry.AddressList;
}
else
{
// Rotate the list of addresses
addresses = new IPAddress[entry.AddressList.Length];
entry.AddressList.AsSpan(index).CopyTo(addresses);
entry.AddressList.AsSpan(0, index).CopyTo(addresses.AsSpan(index));
}
}
// Connect to the remote host
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
{
// Turn off Nagle's algorithm since it degrades performance in most HttpClient scenarios.
NoDelay = true
};
try
{
await socket.ConnectAsync(addresses, context.DnsEndPoint.Port, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var httpClient = new HttpClient(sockerHttpHandler, disposeHandler: true);
C#
await httpClient.GetStringAsync("https://www.bing.com");
#Additional resources
Do you have a question or a suggestion about this post? Contact me!