2.20.3

(fix): Fix useDefaultRequestParameterValues to only apply defaults to query parameters and headers, not to inlined request body properties.


2.20.2

(fix): Wire test assertions now use JSON element comparison instead of object equality, resolving false failures when comparing collections inside undiscriminated union types.

(fix): Fix mock response data generation to omit null values for optional-but-not-nullable properties, matching SDK serialization behavior.

(fix): Fix nullability warning (CS8764) in undiscriminated union JsonConverter by using non-optional return type for ReadAsPropertyName method.

2.20.1

(fix): Fix ambiguous type references (CS0104) for sub-client interfaces when multiple sub-clients share the same name in different namespaces.

(fix): Fix duplicate implicit conversion operators (CS0557) for undiscriminated unions with multiple variants that resolve to the same type.

(fix): Add transitive implicit conversion operators for nested undiscriminated unions.

2.20.0

(chore): Remove .NET 6 (EOL 2024/10/12) and 7 (EOL 2024/05/14) target frameworks from generated SDKs as they are no longer supported by Microsoft. The generated SDKs now only target .NET Framework 4.6.2, .NET Standard 2.0, and .NET 8.

2.19.7

(fix): Top-level clients now use interface types for sub-clients instead of concrete types.

2.19.6

(fix): Fix wire test generation to preserve string field values that contain datetime-like strings.


2.19.5

(fix): Fix missing client-level headers for endpoints without endpoint-specific headers.

Previously, endpoints that didn’t have endpoint-specific headers (like custom request headers) would not include client-level headers (API key, SDK version, additional headers) in their HTTP requests. This caused authentication failures for APIs that rely on headers set at the client level.

The fix ensures that all endpoints now properly merge headers from:

  • Client options headers (API key, SDK version, etc.)
  • Client additional headers (user-provided at client construction)
  • Request options additional headers (user-provided per-request)

2.19.4

(fix): Fix missing [Optional] and/or Nullable attributes on generated properties with defaults.

2.19.3

(fix): Fully unwrap optional-nullable wrappers when generating undiscriminated unions.

2.19.2

(fix): Fixes missing references to Core utilities in interface files for the Optional wrapper.

2.19.1

(fix): Fix nullable element types in collections to correctly preserve nullable markers.

Previously, nullable types nested inside collections would incorrectly strip the inner nullable marker:

  • nullable<list<nullable<string>>> incorrectly generated IEnumerable<string>?
  • nullable<map<string, nullable<Address>>> incorrectly generated Dictionary<string, Address>?

Now generates correctly:

  • nullable<list<nullable<string>>> generates IEnumerable<string?>?
  • nullable<map<string, nullable<Address>>> generates Dictionary<string, Address?>?
  • optional<map<string, nullable<string>>> generates Dictionary<string, string?>?

2.19.0

(feat): Add support for type-safe undiscriminated unions with the new use-undiscriminated-unions configuration option.

Undiscriminated unions provide a clean, type-safe way to work with values that can be one of several types:

1// Creating union values
2var response = MyUnion.FromString("hello");
3var response = MyUnion.FromInt(42);
4var response = MyUnion.FromCustomObject(new CustomObject { ... });
5
6// Type-safe value access with Is* properties and As* methods
7if (response.IsString)
8{
9 string value = response.AsString();
10 Console.WriteLine($"Got string: {value}");
11}
12else if (response.IsInt)
13{
14 int value = response.AsInt();
15 Console.WriteLine($"Got integer: {value}");
16}
17
18// Safe extraction with TryAs* pattern (no exceptions)
19if (response.TryAsCustomObject(out var obj))
20{
21 Console.WriteLine($"Got object: {obj.Name}");
22}

This provides better IntelliSense support and compile-time safety compared to working with generic object types.

(chore): Reduce NuGet package dependencies. The OneOf library is no longer required when undiscriminated unions are not used, resulting in smaller package sizes and fewer transitive dependencies.

2.18.1

(fix): While most <s and >s should be escaped to &lt; and &gt; to avoid mangling the output, genuine XML/HTML tags should be kept as-is; this commit scans for potential valid tags and prevents their being escaped. (Ambiguous cases are escaped.)

Before:

/// XMLDoc (C#) (Example of actual XML tags):
/// See &lt;a href="https://example.com/docs"&gt;the docs&lt;/a&gt; for more info.
/// Use &lt;code&gt;getValue()&lt;/code&gt; to retrieve the value.
/// Note: when count &lt; 10 or count &gt; 100, special handling applies.

After:

/// XMLDoc (C#) (Example of actual XML tags):
/// See <a href="https://example.com/docs">the docs</a> for more info.
/// Use <code>getValue()</code> to retrieve the value.
/// Note: when count &lt; 10 or count &gt; 100, special handling applies.

2.17.5

(fix): Fix test equality comparison for nested OneOf values in collections.

Previously, when comparing objects containing List<OneOf<...>> properties (such as RelatedResources in FHIR-style models), the test framework would incorrectly report differences even when the values were identical. This was because the nested OneOf comparer didn’t recursively handle OneOf values within collections.

The fix adds a custom EqualityAdapter that registers itself with the inner NUnitEqualityComparer, enabling proper recursive comparison of nested OneOf values.

2.17.4

(fix): Fix extra properties support for inlined request bodies and improve test equality comparisons.

This fix addresses three issues with the extra-properties: true feature:

  • Inlined request bodies now properly support AdditionalProperties for serialization/deserialization
  • Test snippets now include extra properties from examples for both object types and wrapped requests
  • Added AdditionalPropertiesComparer to handle type mismatches between JsonElement and native C# types in test assertions

2.17.3

(fix): Fix mock server tests to use FormUrlEncodedMatcher for form-urlencoded requests.

Previously, mock server tests used WithBodyAsJson for form-urlencoded requests, which caused test failures because the SDK sends the request body as key=value&key2=value2 format, not JSON. This fix uses WireMock’s FormUrlEncodedMatcher to properly match form-urlencoded request bodies.


2.17.2

(fix): Fix mock server tests to exclude read-only properties from expected request JSON.

Previously, mock server tests included read-only properties (marked with access: read-only) in the expected request JSON, causing test failures because the SDK correctly excludes these properties during serialization. This fix filters out read-only properties at all nesting levels, including within dictionaries, lists, and nested objects.

2.17.1

(fix): Add global::System to Attribute in OptionalAttribute and NullableAttribute.


2.18.0

(feat): Add QueryStringBuilder class for building query strings with proper URL encoding.

Example usage:

1var queryString = new QueryStringBuilder.Builder()
2 .Add("access_token", "abc123")
3 .Add("config_id", "cfg-456")
4 .AddDeepObject("session_settings", new { SystemPrompt = "Hello" })
5 .Build();
6// Result: ?access_token=abc123&config_id=cfg-456&session_settings%5BSystemPrompt%5D=Hello

(chore): Improve header merging logic for better reliability and maintainability.

(chore): Remove additional-properties and experimental-additional-properties configuration options. AdditionalProperties support is now always enabled for all generated SDKs, simplifying the generator and ensuring consistent behavior across all generated code. This feature allows handling of extra/unknown properties in JSON responses.


2.17.0

(feat): Respect defaults set for request parameter values.

When use-default-request-parameter-values: true is configured in generators.yml, the SDK will generate initializers of the form = default for those properties of a record that have defaults. Any property with a default will also have the ‘required’ keyword stripped if it’s there, since users should be allowed to omit it during initialization and rely on the default.


2.16.0

(feat): Add support for accessing raw HTTP response data alongside typed response objects using .WithRawResponse().

HTTP endpoint methods now return WithRawResponseTask<T>, which provides two usage patterns:

  • Default behavior: Direct await returns just the typed data (zero-allocation fast path)
  • Raw response access: Await with .WithRawResponse() returns both data and HTTP metadata

Example usage:

1// Default behavior - returns just the data
2var userData = await client.Users.GetAsync("user-123");
3
4// Access raw response metadata
5var result = await client.Users.GetAsync("user-123").WithRawResponse();
6var data = result.Data;
7var statusCode = result.RawResponse.StatusCode; // HttpStatusCode
8var headers = result.RawResponse.Headers; // ResponseHeaders
9var url = result.RawResponse.Url; // Uri
10
11// Access specific headers (case-insensitive)
12if (headers.TryGetValue("X-Request-Id", out var requestId))
13{
14 Console.WriteLine($"Request ID: {requestId}");
15}
16
17// Check content type and length
18var contentType = headers.ContentType;
19var contentLength = headers.ContentLength;

New types:

  • WithRawResponseTask<T> - Awaitable task wrapper supporting both usage patterns
  • WithRawResponse<T> - Container for data + raw response metadata
  • RawResponse - HTTP response metadata (status code, headers, URL)
  • ResponseHeaders - Case-insensitive header collection with enumeration support

Benefits:

  • Zero overhead when raw response access isn’t needed
  • Backward compatible - implicit conversion to Task<T> supported
  • Type-safe access to HTTP metadata when debugging or logging
  • Case-insensitive header lookups following HTTP standards

2.15.0

(feat): Add support for explicit nullable/optional type handling with the new Optional<T> type.

When experimental-explicit-nullable-optional: true is configured in generators.yml, the SDK will use Optional<T?> for nullable optional fields, enabling three-state semantics for PATCH requests:

  • Undefined: Field not set - won’t be included in the request (leave unchanged on server)
  • Defined with null: Field explicitly set to null - will send null (clear the field on server)
  • Defined with value: Field set to a value - will send the value (update the field on server)

Example usage:

1public class UpdateUserRequest
2{
3 public Optional<string?> Name { get; set; } = Optional<string?>.Undefined;
4 public Optional<string?> Email { get; set; } = Optional<string?>.Undefined;
5}
6
7// Don't send name field (leave unchanged)
8var request1 = new UpdateUserRequest();
9
10// Set name to a value
11var request2 = new UpdateUserRequest { Name = "John" };
12
13// Clear name (send null)
14var request3 = new UpdateUserRequest { Name = null };

The Optional<T> type includes:

  • IsDefined property to check if a value is set
  • Value property to access the value (throws if undefined)
  • TryGetValue method for safe value access
  • Implicit conversion operators for ergonomic usage
  • Full JSON serialization support
  • IEquatable<Optional<T>> implementation for proper equality checks

(fix): Fix query parameter serialization to properly handle nullable struct types (DateTime?, DateOnly?, etc.) by adding .Value accessor when needed.

(fix): Improve nullable and optional type handling throughout the generator, including collection value types and type mapping.

2.14.1

(fix): When include-exception-handler: true is configured, the generated exception interceptor class now accepts ClientOptions in its constructor. This allows the interceptor to access client configuration when capturing exceptions.

2.14.0

(feat): Refactor WebSocket API code generation to use composition over inheritance.

Key changes:

  • Replace AsyncApi<T> base class with WebSocketClient internal class using composition
  • Flatten namespace from {root}.Core.Async.* to {root}.Core.WebSockets
  • Generated WebSocket clients now implement IAsyncDisposable, IDisposable, and INotifyPropertyChanged directly
  • Store Options and WebSocketClient as private fields instead of using inheritance
  • Forward Status, Connected, Closed, and ExceptionOccurred events from internal client
  • Simplify INotifyPropertyChanged to only notify for Status property changes

This refactoring improves code clarity and reduces complexity.