> 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<T>`,
`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<T>` 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<T>` 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<JsonDocument>(stream);`
so the document is disposed when the method returns.