> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. ## 2.53.0 **`(fix):`** Enforce `global::` prefix on all `System` namespace references in generated code. This prevents CS0118/CS0426 compile errors when customer projects define a type or namespace named `System` (e.g., root namespace `Foo.Net` with a class `System`). All `using System.*` directives and inline `System.*` type references now use `global::System.*`. A CI validation script in seed.yml enforces this going forward. ## 2.52.0 **`(feat):`** Conditionally emit System.Text.Json as a PackageReference only when targeting pre-net8.0 TFMs (netstandard2.0, net462). The package is wrapped in an ItemGroup with an MSBuild IsTargetFrameworkCompatible condition so it is skipped for net8.0+ where it ships in-box. ## 2.51.1 **`(chore):`** Remove dead `#elif NET7_0_OR_GREATER` and `#else` branches inside `QueryStringBuilder` that could only execute on .NET 6 or .NET 7, which are no longer targeted. ## 2.51.0 **`(feat):`** Add `net9.0` target framework to all generated C# SDK projects. The library now targets `net462;net8.0;net9.0;netstandard2.0`, enabling `#if NET9_0_OR_GREATER` code paths such as `ClientWebSocketOptions.KeepAliveTimeout` for transport-level dead connection detection. Test projects now target `net9.0` instead of `net8.0`. **`(feat):`** Add comprehensive WebSocket unit and end-to-end test templates. All generated WebSocket SDKs now ship with 349 tests covering `AsyncLock`, `Event`, `ReconnectStrategy`, `DisconnectionInfo`, `RequestMessage`, `Query`, `WebSocketConnection`, `WebSocketClient`, `ReconnectionInfo`, and `WebsocketException`. End-to-end tests run against an in-process `TestWebSocketServer` and cover echo, rapid-fire, reconnection, server close, abort recovery, concurrent clients, large messages, and full lifecycle. Templates are conditionally emitted when the Fern definition includes WebSocket endpoints. **`(feat):`** Expose `StateCheckInterval` property on `WebSocketClient`. The property (default: 5 seconds) forwards to `WebSocketConnection` in `ConnectAsync`, allowing callers to control how often the background state monitor polls for silent disconnections. **`(fix):`** Fix server-initiated close skipping reconnection. When the server sent a `WebSocketMessageType.Close` frame, the `Listen()` method used `return` which exited entirely — bypassing the `ReconnectSynchronized` call. Changed to `break` with a `closedByServer` flag so reconnection executes with `ReconnectionType.ByServer`. **`(fix):`** Fix `CancelReconnection` flag being ignored for server-initiated close. The `OnDisconnectionHappened` callback fires in the Close handler and the user can set `info.CancelReconnection = true`, but this flag was never checked before calling `ReconnectSynchronized`. Now captured into a local `cancelReconnect` variable and checked before reconnecting. ## 2.50.0 **`(feat):`** Add exponential backoff reconnection strategy for WebSocket connections. A new `ReconnectStrategy` class provides configurable exponential backoff (doubling intervals from 1s to 60s), optional random jitter (0-25%) to prevent thundering herd, and configurable max attempts. The strategy is exposed as a `ReconnectBackoff` property on the generated Options class and wired through `WebSocketClient` to `WebSocketConnection.Reconnect()`. When max attempts are exhausted, reconnection stops and a disconnection event is raised. The backoff resets on successful reconnection. ## 2.49.0 **`(feat):`** Add per-send timeout to prevent `SendAsync` hangs. A new `SendTimeout` property (default: 30 seconds) on `WebSocketConnection` wraps every `SendAsync` call with a linked `CancellationTokenSource` that fires `CancelAfter(SendTimeout)`. When the timeout elapses the connection is aborted and a `WebsocketException` is thrown, preventing a single dead connection from blocking the send lock for up to 30 minutes. See: [https://github.com/dotnet/runtime/issues/125257](https://github.com/dotnet/runtime/issues/125257) ## 2.48.0 **`(feat):`** Add bounded send queue with message expiration to `WebSocketConnection`. The unbounded `Channel` queues are replaced with configurable bounded channels (`SendQueueLimit`, default: 10,000) that use `BoundedChannelFullMode.DropWrite` to reject new messages when the queue is full. A `SendCacheItemTimeout` property (default: 30 minutes) causes stale messages to be silently dropped during drain, preventing memory growth during network outages and avoiding sending outdated messages after reconnection. Set `SendQueueLimit` to 0 for unbounded or `SendCacheItemTimeout` to null to disable expiration. ## 2.47.0 **`(feat):`** Add receive hang detection via a background state monitor task. A new `StateCheckInterval` property (default: 5 seconds) controls how often the monitor polls `WebSocket.State`. When the state transitions to `Closed`, `Aborted`, or `CloseReceived` — indicating the TCP connection died without notifying the receive loop — the monitor cancels the pending `ReceiveAsync` via a linked `CancellationTokenSource`. This works around known .NET runtime issues where `ReceiveAsync` hangs indefinitely on silent TCP disconnections (dotnet/runtime#110496) and `Abort()` fails to cancel a pending receive (dotnet/runtime#44272). Set `StateCheckInterval` to `null` to disable. ## 2.46.0 **`(feat):`** Wire up WebSocket reconnection logic. The `WebSocketConnection` template now contains a complete reconnection implementation ported from the Marfusios library: heartbeat timer (`ReconnectTimeout`), error-retry timer (`ErrorReconnectTimeout`), lost-connection delay (`LostReconnectTimeout`), and `Reconnect()`/`ReconnectOrFail()` public methods. The generated WebSocket API classes expose a `Reconnecting` event and an `IsReconnectionEnabled` option (default: `false`) so callers can opt in to automatic reconnection. All timeout properties are configurable with sensible defaults. ## 2.45.1 **`(fix):`** Fix sticky compression on reconnect. `DeflateOptions` is now explicitly reset to `null` when `EnableCompression` is `false`, preventing a previous non-null value from persisting across connection cycles. ## 2.45.0 **`(feat):`** Add `InjectTestMessage` internal method to generated WebSocket client classes. This allows unit tests to simulate incoming WebSocket messages by injecting raw JSON strings through the normal `OnTextMessage` pipeline without requiring a real WebSocket connection. The method is marked `internal` so it is only accessible via `[InternalsVisibleTo]` in test projects, keeping the public API surface clean. ## 2.44.0 **`(feat):`** Add queued sending via `Channel` to the WebSocket connection layer. Two unbounded channels (text and binary) are drained by dedicated background tasks started alongside the connection. The non-blocking `Send(string)` and `Send(byte[])` methods return `bool` indicating whether the message was queued, while the existing `SendInstant` async-per-send path remains unchanged. Queues are completed in `Dispose` before cancellation tokens are signalled. Drain loop errors are surfaced through the `ExceptionOccurred` event. ## 2.43.0 **`(feat):`** Add per-message deflate compression support (RFC 7692) for WebSocket connections. A new `EnableCompression` option on the generated WebSocket Options class enables `WebSocketDeflateOptions` via `ClientWebSocketOptions.DangerousDeflateOptions`. This can significantly reduce bandwidth for text-heavy (JSON) WebSocket APIs. Warning: Do not use compression when sending data containing secrets (CRIME/BREACH vulnerability). See [https://learn.microsoft.com/dotnet/api/system.net.websockets.clientwebsocketoptions.dangerousdeflateoptions](https://learn.microsoft.com/dotnet/api/system.net.websockets.clientwebsocketoptions.dangerousdeflateoptions) for details. ## 2.42.0 **`(feat):`** Add support for HTTP/2 WebSockets via `SocketsHttpHandler`. A new `HttpInvoker` property on the WebSocket Options class allows passing an `HttpMessageInvoker` to enable multiplexing multiple WebSocket streams over a single TCP connection. When set, the connection factory configures `HttpVersion.Version20` and uses the `ConnectAsync(Uri, HttpMessageInvoker, CancellationToken)` overload on .NET 7+. On older targets the invoker is ignored and the standard connect path is used. ## 2.41.0 **`(feat):`** Add `ConnectTimeout` property to `WebSocketConnection` and `WebSocketClient` with a default of 5 seconds. The connection factory call in `StartClient` now uses a linked `CancellationTokenSource` with `CancelAfter(ConnectTimeout)`, preventing indefinite hangs when the server is unresponsive. ## 2.40.0 **`(feat):`** Configure PING/PONG keep-alive on `ClientWebSocket`. The default connection factory now sets `KeepAliveInterval` (default: 30 s) and, on .NET 9+, `KeepAliveTimeout` (default: 20 s) to enable the PING/PONG keep-alive strategy that detects unresponsive servers at the transport level. Both values are exposed as public properties on `WebSocketConnection` for caller customization. ## 2.38.2 **`(fix):`** Add `using` declaration to `JsonDocument` in WebSocket `OnTextMessage` handler. `JsonDocument` implements `IDisposable` and holds pooled memory buffers; without disposal, high message throughput causes memory pressure. The generated code now emits `using var json = await JsonSerializer.DeserializeAsync(stream);` so the document is disposed when the method returns.