Skip to content
1 GB of residential proxies, free. $0 today, card required.
Handler routing runbook

.NET HttpClient Proxy Setup in C#: WebProxy and SOCKS5

Set a C# HttpClient proxy with WebProxy, SocketsHttpHandler, DefaultProxy or IHttpClientFactory, verify the exit, and separate 407, DNS, TLS and timeout failures by hop.

.NET HttpClient → DatabayOne handler owns the proxy, credential and pool
.NET HttpClientHTTP client library
Databay gateway modesClient support is covered below
gw.databay.co:8888
By Databay Research Team11 min runbook

Operating principle

Set the WebProxy and credential on the handler each HttpClient owns, so environment defaults, pooling and timeouts stay explicit per route.

Route One HttpClient Through the Databay Gateway

An HttpClient has no proxy property of its own: the handler passed to its constructor carries the route, so a WebProxy set there fixes it in code instead of inheriting it from the machine. Use it only for destinations you own or are authorized to access, and follow each destination's terms.

Databay's gateway, gw.databay.co on port 8888, handles HTTP proxying, HTTPS CONNECT tunnelling and SOCKS5, but not UDP. This .NET 8 console program reads the dashboard-issued credential from injected environment variables and observes the exit before any real destination:

// Program.cs (.NET 8 console app)
using System.Net;

string user = Environment.GetEnvironmentVariable("DATABAY_PROXY_USER")
    ?? throw new InvalidOperationException("DATABAY_PROXY_USER is not set");
string pass = Environment.GetEnvironmentVariable("DATABAY_PROXY_PASS")
    ?? throw new InvalidOperationException("DATABAY_PROXY_PASS is not set");

var proxy = new WebProxy("http://gw.databay.co:8888")
{
    Credentials = new NetworkCredential(user, pass)
};
var target = new Uri("https://api.ipify.org?format=json");

var handler = new SocketsHttpHandler
{
    Proxy = proxy,
    UseProxy = true,
    ConnectTimeout = TimeSpan.FromSeconds(10),
    PooledConnectionLifetime = TimeSpan.FromMinutes(5)
};
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) };

Console.WriteLine(await client.GetStringAsync(target));

The proxy URI uses http:// for an https:// destination because that scheme describes the client-to-gateway hop: HttpClient opens a CONNECT tunnel and negotiates destination TLS inside it, so certificate validation stays end to end. A non-2xx answer makes GetStringAsync throw HttpRequestException with StatusCode set. The printed JSON is the exit observed for one request, not proof of anonymity.

Ready to run this for real?

Credentials appear in your dashboard in minutes, on the same gateway and username format this .NET HttpClient guide uses.

Map Databay Values to HttpClient and WebProxy Controls

HttpClientHandler and SocketsHttpHandler share the Proxy, UseProxy and DefaultProxyCredentials members; SocketsHttpHandler, the implementation since .NET Core 2.1, adds ConnectTimeout and PooledConnectionLifetime. A handler-level proxy overrides machine defaults, so this table is the whole routing contract for one client:

HttpClient controlDatabay valueWhat to verify
new WebProxy(address)http://gw.databay.co:8888Host and port only; no user information
WebProxy.Credentialsnew NetworkCredential(user, pass) with the complete dashboard usernameValues come from a secret store; a 407 points here first
Proxy and UseProxyThe WebProxy above; UseProxy = true, the documented defaultNo helper flips UseProxy or swaps the handler
BypassProxyOnLocal and BypassListfalse and empty unless a local host must go directproxy.IsBypassed(target) is false for the check URL
ConnectTimeoutExample: 10 secondsThe documented default is infinite
PooledConnectionLifetimeExample: 5 minutesDefault infinite; caps how long a connection, and possibly an exit, is reused
HttpClient.TimeoutExample: 30 secondsDefault 100 seconds per request
DefaultRequestVersion and DefaultVersionPolicyLeave the defaultsNever require HTTP/3: QUIC needs UDP, which the gateway does not carry

Each row belongs to one handler, which owns one connection pool and one credential. Microsoft's HttpClient guidelines say multiple proxies need separate instances, and handler properties throw InvalidOperationException once a request has started, so build one handler per Databay username: one handler, one routing policy.

How HttpClient.DefaultProxy Reads the Environment and System

A handler with no Proxy, such as a plain new HttpClient(), uses the static HttpClient.DefaultProxy (.NET Core 3.0 and later), which reads environment variables first, then the user's proxy settings on Windows, system settings on macOS, or direct connections on Linux.

  • HTTP_PROXY and HTTPS_PROXY are chosen by destination scheme, so HTTPS_PROXY governs https:// URLs although its value starts with http://; ALL_PROXY fills any gap.
  • NO_PROXY takes comma-separated host names without asterisk wildcards; matching a subdomain such as www.example.com needs a leading dot, .example.com.
  • Where names are case-sensitive, lowercase variables are checked first.

The reference also accepts http://USER:PASS@gw.databay.co:8888. Avoid it: anything that reads the environment reads the password, and the proxy URI that some error messages quote then carries it. Keep the value credential-free and give the handler the credential:

var handler = new SocketsHttpHandler { DefaultProxyCredentials = new NetworkCredential(user, pass) };

var target = new Uri("https://api.ipify.org?format=json");
IWebProxy selected = HttpClient.DefaultProxy;
Uri? via = selected.IsBypassed(target) ? null : selected.GetProxy(target);
Console.WriteLine(via is null ? "direct" : $"{via.Host}:{via.Port}"); // never the full URI

On Windows those settings can include Automatically detect settings, which typically uses WPAD and a PAC script, and a service account may not share your interactive settings. DefaultProxy rejects null, so a client that must stay direct needs UseProxy = false on its own handler.

Keep Direct-Route Exceptions Narrow and Tested

WebProxy has its own exception rules, separate from NO_PROXY. Microsoft documents BypassList entries as regular expressions describing URIs, not wildcard host names, so escape dots and anchor each pattern, for example @"^https://status\.internal\.example(:\d+)?$". The exact text being matched is an implementation detail, so pin every rule with an IsBypassed assertion in a unit test.

BypassProxyOnLocal = true sends local destinations direct: flat names without a dot, loopback or local-machine addresses, and hosts sharing the computer's domain suffix. Left false, nothing local is exempted, so a proxied call to a localhost sidecar goes to the gateway too. Often the cleaner design is two clients: one proxied for external destinations and one with UseProxy = false for internal services.

Register Proxied Clients With IHttpClientFactory in ASP.NET Core

In ASP.NET Core, register one named client per routing policy and build its primary handler in ConfigurePrimaryHttpMessageHandler, whose delegate should return a new handler on every call. Microsoft's IHttpClientFactory guidance pairs it with SocketsHttpHandler: PooledConnectionLifetime recycles connections, so the factory's two-minute default handler rotation can be disabled with SetHandlerLifetime(Timeout.InfiniteTimeSpan).

// Program.cs: ASP.NET Core on .NET 8
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient("databay-residential-us", client =>
        client.Timeout = TimeSpan.FromSeconds(30))
    .ConfigurePrimaryHttpMessageHandler(sp =>
    {
        IConfiguration config = sp.GetRequiredService<IConfiguration>();
        string Secret(string key) =>
            config[key] ?? throw new InvalidOperationException($"{key} is missing");

        return new SocketsHttpHandler
        {
            Proxy = new WebProxy("http://gw.databay.co:8888")
            {
                Credentials = new NetworkCredential(
                    Secret("Databay:ProxyUser"), Secret("Databay:ProxyPass"))
            },
            ConnectTimeout = TimeSpan.FromSeconds(10),
            PooledConnectionLifetime = TimeSpan.FromMinutes(5)
        };
    })
    .SetHandlerLifetime(Timeout.InfiniteTimeSpan);

Resolve the keys from the Secret Manager (dotnet user-secrets) in development and a vault or platform secret injection in production, never a committed appsettings.json. Consumers call CreateClient with the name per unit of work. Never register a client per sticky session: Microsoft warns that unbounded client names can exhaust resources. Pooled handlers share their CookieContainer, so cookie-dependent work needs its own clients, and with an infinite handler lifetime a rotated password applies only after a restart.

Switch the Same Client to SOCKS5 on .NET 6 or Later

Microsoft's .NET 6 networking improvements post introduced SOCKS4, SOCKS4a and SOCKS5 support in SocketsHttpHandler, selected by the proxy URI's scheme. Pass the full URI to the single-string WebProxy constructor; the post's footnote notes that the host-and-port overload accepted only HTTP proxies until .NET 7.

// .NET 6 or later: SOCKS5 on the same gateway port
var socksHandler = new SocketsHttpHandler
{
    Proxy = new WebProxy("socks5://gw.databay.co:8888")
    {
        Credentials = new NetworkCredential(user, pass)
    },
    ConnectTimeout = TimeSpan.FromSeconds(10)
};
using var socksClient = new HttpClient(socksHandler);
Console.WriteLine(await socksClient.GetStringAsync("https://api.ipify.org?format=json"));

The DefaultProxy reference lists an optional username and password for socks5 URLs and says socks4 and socks4a ignore the password, so only SOCKS5 fits a Databay credential; supply it through WebProxy.Credentials and confirm the exit with one request. Microsoft does not document where SOCKS5 destination names are resolved, so test that if it matters. SOCKS5 adds no encryption; destination TLS still protects HTTPS, as the HTTP versus SOCKS5 comparison explains.

Timeouts, Connection Reuse and Databay Session Usernames

Three budgets interact. HttpClient.Timeout, 100 seconds by default, covers each whole request; a CancellationToken sets a per-call budget, and the Timeout reference notes that only the shorter applies. ConnectTimeout is infinite by default, so bound it. An expired HttpClient.Timeout surfaces as TaskCanceledException with an inner TimeoutException; your own cancellation shows as IsCancellationRequested on its token source.

Pooling decides how long an exit can persist: a new proxy connection may select an available exit, a reused connection or tunnel may keep the same one, and neither outcome is promised. PooledConnectionLifetime retires a connection after the configured age once its current request finishes, and factory handler rotation has a similar effect; do not tune either to manufacture rotation or continuity. Put that intent in the dashboard-issued username, such as USER-zone-residential-countryCode-us, or USER-zone-residential-countryCode-us-sessionId-abc123 for a sticky session.

Give each sticky workflow its own handler, dispose it when the workflow ends, and stay within the requested window. Premium Residential and Residential Flex support requests up to 1440 minutes where available. Datacenter and Mobile support requests up to 120 minutes. The IP can change before the window ends. Premium Residential accepts one country, state, city, ZIP, coordinate or ASN selector at a time; Residential Flex, Datacenter and Mobile target country or continent, and every pool is shared. Copy the complete username from the dashboard rather than inventing grammar, and never change sessions in response to 401, 403, 407 or 429.

Verify the Exit, Then Triage HttpClient Failures by Hop

Before the real destination, request https://api.ipify.org?format=json or Databay's https://databay.com/what-is-my-ip/json through the configured client, then repeat with a UseProxy = false client as a control. Record RuntimeInformation.FrameworkDescription, proxy scheme, UTC time and observed address, and check a country-targeted route's location on the What Is My IP page.

When a call fails, filter on the documented HttpRequestError category (.NET 8 and later), for example catch (HttpRequestException ex) when (ex.HttpRequestError == HttpRequestError.ProxyTunnelError):

EvidenceHopNext safe check
NameResolutionErrorProxy hop: resolving gw.databay.coThe gateway resolves proxied destinations, so check the gateway name, the resolver, or a request sent direct.
ConnectionErrorProxy hop: TCP to port 8888Egress firewall, network policy and outbound port 8888.
ProxyTunnelError naming 407, or a response with HttpStatusCode.ProxyAuthenticationRequiredProxy hop: authenticationRe-copy the complete username and password into WebProxy.Credentials, or DefaultProxyCredentials for the default proxy.
ProxyTunnelError with another status, or a failed SOCKS handshakeProxy hop: tunnelKeep the status, test one allowed destination, and do not switch routes to get around a refusal.
SecureConnectionErrorDestination hop: TLS inside the tunnelCheck the trust store, clock and any inspection appliance. Never assign a ServerCertificateCustomValidationCallback that returns true.
TaskCanceledException with an inner TimeoutExceptionTime budgetCompare ConnectTimeout with HttpClient.Timeout, then retry once with a justified budget.
Destination 401, 403 or 429Destination hop: authorization or rate controlStop, use the official API or approved access path, and honor Retry-After.

For an https:// destination, a gateway 407 arrives while the CONNECT tunnel is being built, so it surfaces as an exception; a 407 response object appears only for http:// destinations. On .NET 8 the status appears only in the exception message, while newer runtimes also fill StatusCode; earlier runtimes lack HttpRequestError, so inspect InnerException. If the same credential works in the cURL proxy runbook but fails here, the fault is likely in application configuration.

Keep the Proxy Credential Out of Code, Logs and Screens

Treat the Databay password like any production secret: keep it out of source, committed configuration, container images, command lines and proxy URLs, inject it at run time from a secret store, and limit which jobs can read it. Never add a Proxy-Authorization header by hand; the handler answers the gateway's challenge from WebProxy.Credentials.

Log routing facts, not secrets: gateway host and port, scheme, HttpRequestError, status and observed exit, never a NetworkCredential, raw environment variable or full proxy URI. Redact terminal recordings, debugger screenshots and tickets before sharing, and rotate the credential after any exposure.

Troubleshooting desk

Questions specific to .NET HttpClient

How do I set a proxy for HttpClient in C#?
Create a WebProxy with the gateway address, set its Credentials to a NetworkCredential holding the dashboard username and password, assign it to the Proxy property of a SocketsHttpHandler or HttpClientHandler, and pass that handler to the HttpClient constructor. Then request an IP echo endpoint through the client to observe the exit before contacting the real destination.
Why does a wrong proxy password throw instead of returning a 407 response?
For an https:// destination, HttpClient first asks the gateway to open a CONNECT tunnel. When the gateway refuses the tunnel, the handler throws HttpRequestException instead of returning a response; on .NET 8 and later its HttpRequestError property reports ProxyTunnelError. A 407 response object appears only when the destination itself is http://.
Does HttpClient use HTTP_PROXY and HTTPS_PROXY automatically?
Yes, when the handler has no explicit Proxy. On .NET Core 3.0 and later, HttpClient.DefaultProxy reads HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY, then falls back to the user's proxy settings on Windows or the system settings on macOS; on Linux it connects directly. An explicit Proxy on the handler overrides all of these sources.
Which .NET version supports SOCKS5 in HttpClient?
.NET 6 added SOCKS4, SOCKS4a and SOCKS5 support to SocketsHttpHandler. Pass the full socks5:// URI to the single-string WebProxy constructor and set Credentials as you would for HTTP. Microsoft's DefaultProxy reference lists a username and password for socks5 and says socks4 and socks4a ignore the password.
Should a proxied client come from IHttpClientFactory or a long-lived HttpClient?
Either works. Microsoft recommends long-lived clients with PooledConnectionLifetime set, or short-lived clients created by IHttpClientFactory. With the factory, build the proxied SocketsHttpHandler in ConfigurePrimaryHttpMessageHandler, register one named client per routing policy, and never derive client names from unbounded input such as session IDs.
Can I return true from ServerCertificateCustomValidationCallback to fix SSL errors through a proxy?
No. Through an HTTP proxy, destination TLS is negotiated inside the CONNECT tunnel, so the certificate still comes from the destination or from something intercepting the path. Accepting every certificate hides that evidence. Keep validation on and check the trust store, the system clock and any inspection appliance instead.
Adjacent runbooks

Same gateway, different control surface

  • cURL

    Command-line client

    curl -> proxy auth -> CONNECT or SOCKS -> approved destination

  • Node.js fetch

    HTTP client library

    fetch -> env opt-in or same-package dispatcher -> proxy evidence

  • Python Requests

    HTTP client library

    Session -> HTTPAdapter policy -> proxy hop -> approved destination

  • Go net/http

    HTTP client library

    http.Client -> Transport.Proxy -> CONNECT or SOCKS5 -> observed exit

  • Java HttpClient

    HTTP client library

    HttpClient.Builder -> ProxySelector.of -> Authenticator on 407 -> observed exit

  • PHP Guzzle and cURL

    HTTP client library

    Guzzle option or CURLOPT -> libcurl handle -> CONNECT or SOCKS5 -> observed exit

Pick the network once the route works. Residential for home-connection exits with state, city, ZIP and ASN targeting; datacenter for fast server IPs on public websites. Switching is one word in the username.

Residential →Datacenter →

Where teams run .NET HttpClient behind the gateway: Proxies for web scraping · Proxies for market research

Ship .NET HttpClient to production

Create an account, drop in your gateway credentials, and route your first .NET HttpClient request in minutes.

Pricing, order minimums, and traffic validity vary by product.