I recently encountered an issue where connecting to a server over IPv6 was significantly slower than IPv4 (over 2 seconds to open the socket). Forcing the client to use IPv4 resolved the problem. In my case, localhost was not listening on IPv6 on one specific machine. Here is how to force HttpClient to use IPv4 in .NET.
Starting with .NET 5, you can configure how HttpClient creates the socket to communicate with the server using SocketsHttpHandler. This gives you full control over DNS resolution and IP address selection.
C#
var client = new HttpClient(new SocketsHttpHandler()
{
ConnectCallback = async (context, cancellationToken) =>
{
// Use DNS to look up the IP addresses of the target host:
// - IP v4: AddressFamily.InterNetwork
// - IP v6: AddressFamily.InterNetworkV6
// - IP v4 or IP v6: AddressFamily.Unspecified
// note: this method throws a SocketException when there is no IP address for the host
var entry = await Dns.GetHostEntryAsync(context.DnsEndPoint.Host, AddressFamily.InterNetwork, cancellationToken);
// Open the connection to the target host/port
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
// Turn off Nagle's algorithm since it degrades performance in most HttpClient scenarios.
socket.NoDelay = true;
try
{
await socket.ConnectAsync(entry.AddressList, context.DnsEndPoint.Port, cancellationToken);
// If you want to choose a specific IP address to connect to the server
// await socket.ConnectAsync(
// entry.AddressList[Random.Shared.Next(0, entry.AddressList.Length)],
// context.DnsEndPoint.Port, cancellationToken);
// Return the NetworkStream to the caller
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
});
var response = await client.GetStringAsync("https://google.com");
Console.WriteLine(response);
Note that there is currently no callback for QUIC (HTTP/3) connections. Follow this GitHub issue if you are interested in customizing HTTP/3 connections.
Starting with .NET 5, you can also set the environment variable DOTNET_SYSTEM_NET_DISABLEIPV6 to true or the runtime configuration System.Net.DisableIPv6 to disable IPv6 support (documentation).
On Windows, you can also configure the system to prefer IPv4 or IPv6 by setting the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\DisabledComponents (DWORD) to one of the following values:
0x20: Prefer IPv4 over IPv6xx0x xxxx: Prefer IPv6 over IPv4
#Additional resources
Do you have a question or a suggestion about this post? Contact me!