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

**`(feat):`** Add `unified-client-options` configuration flag. When enabled, all auth parameters,
global headers, and `BaseUrl` are consolidated into `ClientOptions` so the client
constructor takes a single argument with no positional parameters:

```yaml
# generators.yml
groups:
  dotnet-sdk:
    generators:
      - name: fernapi/fern-csharp-sdk
        config:
          unified-client-options: true
```

**Before** (default):

```csharp
var client = new MyClient(
    "my-api-key",
    clientOptions: new ClientOptions { BaseUrl = "..." }
);
```

**After** (with `unified-client-options: true`):

```csharp
var client = new MyClient(
    new ClientOptions
    {
        ApiKey = "my-api-key",
        BaseUrl = "https://api.example.com",
    }
);
```

Supported auth schemes: bearer token, basic auth (username/password), header auth,
OAuth client credentials (clientId/clientSecret + custom params), and inferred auth.
Global headers (non-literal) are also included.

Properties on `ClientOptions` use the appropriate C# semantics based on the
parameter's characteristics:

* **Has environment variable fallback** — `public string? ApiKey { get; set; }`.
  Nullable and mutable so the constructor can apply the fallback via
  `clientOptions.ApiKey ??= GetFromEnvironmentOrThrow(...)`.
* **Optional (no environment variable)** — `public string? ApiKey { get; init; }`.
  Nullable, immutable after construction.
* **Required (no environment variable, not optional)** — `public required string ApiKey { get; init; }`.
  Non-nullable, enforced at the call site by the compiler. `BaseUrl` is also
  `required` when no default environment is configured, replacing the previous
  behavior of silently defaulting to `""`.

When any `ClientOptions` field is `required`, the constructor parameter becomes
non-nullable (`ClientOptions clientOptions` instead of `ClientOptions? clientOptions = null`),
and `Clone()` uses an internal copy constructor annotated with `[SetsRequiredMembers]`.

## 2.33.1

**`(fix):`** Fix README generation to use the `package-name` field from `generator.yml` for the
NuGet package name in installation instructions and shields. Previously, the README
always used the namespace (or `package-id` custom config) instead of the configured
`package-name`, which is the actual NuGet package identifier.

## 2.33.0

**`(feat):`** WebSocket factory methods now resolve the base URL from the main client's
multi-URL environment when the channel specifies a `baseUrl`. This allows
WebSocket clients to use environments defined on the root client (e.g.,
`Environment.Wss`) instead of requiring separate per-WebSocket environment
classes.

## 2.32.2

**`(fix):`** Fix CS1501 build error for literal struct `GetHashCode` on `netstandard2.0` and
`net462` targets. `string.GetHashCode(StringComparison)` is only available in
.NET Core 2.1+ / .NET Standard 2.1+. The generated code now uses
`StringComparer.Ordinal.GetHashCode(Value)` which is available on all frameworks.

## 2.32.1

**`(fix):`** Fix referenced request bodies with `application/x-www-form-urlencoded` content type
to generate `FormRequest` instead of `JsonRequest`. Previously, endpoints using a
`$ref` schema with form-urlencoded content type would incorrectly send JSON-serialized
bodies, causing auth token requests (e.g., OAuth) to fail.