2.56.5

(fix): Fix mock server test generation to omit null values for non-nullable properties in inlined request bodies, matching the SDK’s JsonIgnoreCondition.WhenWritingNull serialization behavior. When enableExplicitNullableOptional is disabled (default), all nulls are now unconditionally omitted from expected request JSON.

(fix): Fix pagination test build errors (CS8411) when generatePaginatedClients is disabled. The test generator now checks the config flag before emitting await foreach code, preventing attempts to iterate over plain response types that do not implement IAsyncEnumerable.


2.56.4

(fix): Fix duplicate field error in wrapped request generation when an inlined request body property has the same PascalCase name as a path parameter (e.g., upload_request_id body property colliding with uploadRequestId path parameter). When a collision is detected, the path parameter field ([JsonIgnore]) is skipped and the body property ([JsonPropertyName]) is kept, so the single property serializes to both the URL path and the JSON request body.

2.56.3

(chore): Remove legacy backslash escape in generated CI workflow’s NuGet publish step now that Eta template engine does not interpret ${} syntax.

2.56.2

(fix): Make query-string and path parameter encoding RFC 3986 spec-compliant with three distinct encoding contexts: path segments (pchar), query keys, and query values. Each context now encodes exactly the characters that RFC 3986 requires. Query keys exclude &, =, +, #; query values exclude &, +, # (but allow =); path segments allow all sub-delimiters plus : and @ (but encode / and ?). Path parameter values are now percent-encoded via EncodePathSegment in ValueConvert.ToPathParameterString. Previously, all contexts shared a single character set and path parameters were not encoded.

2.56.1

(chore): Use a persistent CSharpier process for code formatting. Instead of spawning a new process per format call, a single csharpier pipe-files process is kept alive and files are piped to it on demand. This eliminates repeated .NET startup overhead and significantly speeds up formatting during SDK generation.

2.56.0

(feat): Add maxRetries custom config option to override the default maximum number of retries for failed requests. The default remains 2 when not specified.


2.57.0-rc.0

(feat): Upgrade to IR v66 which compresses the IR Name type, reducing IR size and increasing performance.

2.55.4

(fix): Fix C# compilation errors (CS0118) in generated subpackage clients where a type name collides with a namespace segment. Type references are now fully qualified to avoid ambiguity.

2.55.3

(chore): Upgrade WireMock.Net from 1.25.0 to 2.2.0 in generated test projects. This is a test-only dependency and does not affect the shipped SDK.


2.55.2

(fix): Support multiple Basic Auth schemes with AuthSchemesRequirement.Any. When an API defines more than one basic auth scheme (e.g., accountId/authToken and apiKey/apiKeySecret), the generated client now produces conditional if/else if blocks that check which credential pair was provided and sets the Authorization header accordingly. Previously, only the first basic auth scheme was used.

2.55.1

(fix): Include extraProperties (AdditionalProperties) in WireMock mock server response objects. Previously, object types with [JsonExtensionData] additional properties were missing those properties in generated mock responses, causing incomplete WireMock stubs.


2.55.0

(feat): Add Environments section to generated README showing how to select different environments (production/sandbox) when initializing the client.


2.54.7

(fix): Wire Basic Auth credentials into the Authorization header. Previously, the generated client accepted username/password constructor parameters but never set the Authorization: Basic <base64> header on outgoing requests. The constructor now encodes the credentials and adds the header automatically.


2.54.6

(chore): Upgrade test infrastructure NuGet packages in generated C# SDK test projects. These are test-only dependencies and do not affect the shipped SDK.

  • Microsoft.NET.Test.Sdk: 17.13.0 → 18.3.0
  • NUnit: 4.3.2 → 4.5.1
  • NUnit3TestAdapter: 5.0.0 → 6.2.0
  • NUnit.Analyzers: 4.6.0 → 4.12.0
  • coverlet.collector: 6.0.4 → 8.0.1
  • WireMock.Net: 1.7.4 → 1.25.0

2.54.5

(chore): Upgrade BCL/runtime NuGet package versions in generated C# SDKs. All packages remain within the 9.x line for net8.0 compatibility.

  • Portable.System.DateTimeOnly: 8.0.2 → 9.0.1
  • System.Text.Json: 8.0.5 → 9.0.9 (legacy TFM conditional)
  • Microsoft.Extensions.Logging.Abstractions: 8.0.2 → 9.0.13 (WebSocket)
  • System.Threading.Channels: 8.0.0 → 9.0.13 (WebSocket)
  • System.Net.ServerSentEvents: 9.0.9 → 9.0.14 (SSE)

2.54.4

(fix): Thread endpoint ID through dynamic snippet generator to differentiate generated snippets by endpoint.

2.54.3

(fix): Fix C# dynamic snippets using the internal client class name (client-class-name) instead of the exported client class name (exported-client-class-name). When both config options are set (e.g., client-class-name: BasePayrocClient and exported-client-class-name: PayrocClient), generated snippets now correctly use PayrocClient in user-facing code.


2.54.2

(fix): Replace Activator.CreateInstance<TConverterType>() with new TConverterType() in CollectionItemSerializer. The new() generic constraint allows compile-time instantiation, removing the reflection-based call that is not AOT-safe.

2.54.1

(chore): Remove the generic EnumSerializer<T> template that used reflection (GetField, GetCustomAttributes) at runtime. All enums already use per-enum generated serializers with static dictionary lookups, so the generic template was dead code. This cleanup removes the last reflection-based enum serialization path, improving NativeAOT and IL-trimming compatibility.


2.54.0

(feat): Support x-fern-server on AsyncAPI channels for multi-URL environments. When a channel specifies a baseUrl (via x-fern-server) that maps to a multi-URL environment in the IR, the C# generator now automatically derives websocket environments from the IR’s environment definitions. This eliminates the need for the temporary-websocket-environments workaround in generators.yml.


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

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 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.