Originally published on proxymint.
C# HttpClient proxy setup for .NET 8 and 10: WebProxy credentials, SOCKS5, environment proxies, IHttpClientFactory, rotation and the 407 and https:// traps.
TL;DR
- A WebProxy on the handler is the whole setup. Create new WebProxy("http://HOST:PORT") with a NetworkCredential on its Credentials property, assign it to SocketsHttpHandler.Proxy or HttpClientHandler.Proxy with UseProxy = true, and pass the handler to HttpClient.
- Credentials in the proxy URL are ignored by WebProxy. new WebProxy("http://USERNAME:PASSWORD@HOST:PORT") still gets a 407. The HTTPS_PROXY environment variable is the one place where user:pass in the address is read as credentials.
- SOCKS5 works from .NET 6 with a socks5:// address. socks5h:// throws NotSupportedException, but .NET's socks5 already sends the hostname, so DNS resolves at the proxy.
- Never write https:// in the proxy address. On .NET 8 and 10 it means TLS to the proxy itself, so an ordinary proxy port either stalls until the timeout or fails at once with an SSL error.
Key takeaways
- Keep one long-lived HttpClient per proxy. Handler properties freeze after the first request, and a new client per request repeats the 407 round trip, the TLS handshake and the socket setup.
- Set ConnectTimeout on SocketsHttpHandler. A wrong proxy address then fails in seconds, as a TaskCanceledException whose inner TimeoutException names ConnectTimeout, instead of after the 100-second HttpClient default.
- Write BypassList entries as regular expressions. Escape the dots and allow an optional port, for example \.internal\.example(:\d+)?$, because a wildcard like *.corp throws.
- Check rotation with and without connection reuse. Compare a pooled client with PooledConnectionLifetime = TimeSpan.Zero against an https:// IP echo endpoint, next to a direct call.
Read the full guide on proxymint, with the commands, tables and sources.
Top comments (0)