Skip to main content

WebSocketClientOptions

All configuration for WebSocketClient lives on Options, a WebSocketClientOptions instance. Set these before calling ConnectAsync.

PropertyTypePlatformDefault
RequestedSubProtocolsICollection<string>bothempty
KeepAliveIntervalTimeSpanbothWebSocket.DefaultKeepAliveInterval (30s)
ReceiveBufferSizeintboth16384
SendBufferSizeintboth16384
IsValidUpgradeHeaderFunc<string?, bool>bothrequires "websocket" (case-insensitive)
IsValidConnectionHeaderFunc<string?, bool>bothaccepts if "Upgrade" is any comma-separated token
IsValidAcceptHeaderFunc<string, string?, bool>bothexact match (case-insensitive) against the computed accept key
ConfigureRequestAction<HttpWebRequest>?net462null
ConfigureRequestAction<HttpRequestMessage>?net5.0null
ConfigureHandlerAction<SocketsHttpHandler>?net5.0null

Sub-protocols​

client.Options.RequestedSubProtocols.Add("chat");

If the server responds with a sub-protocol not in this collection, ConnectAsync throws. This negotiation check itself isn't overridable, only which values you request is.

Validation delegates​

These three are the actual reason this package exists: ClientWebSocket hardcodes its handshake-response validation internally, with no way to relax any of it. WebSocketClient exposes each check as a delegate instead, with defaults that are RFC 6455-compliant, and, for Connection, deliberately more lenient than ClientWebSocket's own check.

IsValidUpgradeHeader​

Validates the Upgrade response header. Default requires it equal "websocket", case-insensitive.

IsValidConnectionHeader​

Validates the Connection response header. This default is the actual fix. ClientWebSocket requires an exact match against "Upgrade"; WebSocketClient's default instead treats the header as a comma-separated token list and accepts it as long as "Upgrade" is one of the tokens. A server responding with Connection: Upgrade, Keep-Alive, spec-legal, but rejected by ClientWebSocket, connects successfully here by default.

Override only if you need to relax or tighten this further, for example to tolerate a non-standard value from a specific service:

client.Options.IsValidConnectionHeader = value =>
(value ?? "").Split(',').Select(t => t.Trim())
.Any(t => string.Equals(t, "Upgrade", StringComparison.OrdinalIgnoreCase));

IsValidAcceptHeader​

Validates the Sec-WebSocket-Accept response header against the value computed from the request's Sec-WebSocket-Key. Default is an exact, case-insensitive match, per RFC 6455.

Why there's no IsValidStatusCode​

Unlike the three delegates above, there's no override for the response status code, it's hardcoded to require 101 Switching Protocols. This is deliberate, not an oversight: per RFC 6455 §4.1, 101 is the actual mechanism by which the connection switches protocols at all. If a server never sends it, the connection never leaves ordinary HTTP semantics, there's no server response shape where relaxing this check would reveal a connection that was secretly fine. Overriding it could only ever suppress WebSocketClient's own clear exception in favor of a confusing one from deeper in the platform (on .NET Framework, WebSocket.CreateClientWebSocket itself rejects a non-upgraded stream as non-writable), it can't retroactively cause a protocol switch that never happened on the wire.

Certificate validation​

For connecting to servers presenting self-signed or otherwise untrusted certificates, use ConfigureRequest (net462) or ConfigureHandler (net5.0):

.NET Framework (net462):

client.Options.ConfigureRequest = request =>
request.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;

Modern .NET (net5.0):

client.Options.ConfigureHandler = handler =>
handler.SslOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true;

Other request/connection configuration​

ConfigureRequest and ConfigureHandler are general-purpose escape hatches, invoked just before the request is sent, for anything not wrapped explicitly above: custom headers, credentials, proxy configuration, client certificates, and so on.

  • net462: ConfigureRequest takes an Action<HttpWebRequest>, request and connection-level settings live on the same object.
  • net5.0: ConfigureRequest takes an Action<HttpRequestMessage> (request-level settings, e.g. custom headers); ConfigureHandler takes an Action<SocketsHttpHandler> (connection-level settings, e.g. proxy, credentials, TLS options). These are separate because modern .NET's networking stack separates connection-level configuration from the request message itself, unlike HttpWebRequest, which bundles both.