Skip to content

[.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors#9920

Draft
Copilot wants to merge 7 commits intomainfrom
copilot/auto-generate-clientsettings-class
Draft

[.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors#9920
Copilot wants to merge 7 commits intomainfrom
copilot/auto-generate-clientsettings-class

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

Automatically generates IConfiguration-based client construction support for every generated client, enabling standard .NET configuration patterns (appsettings.json, environment variables) and dependency injection registration.

What's Generated

A. {Client}Settings class

  • Extends ClientSettings (from System.ClientModel.Primitives)
  • Properties for endpoint URI, non-auth required constructor parameters, and client options
  • Implements BindCore(IConfigurationSection section) override
  • Marked [Experimental("SCME0002")]

B. internal {Client}Options(IConfigurationSection section) constructor

  • Calls base(section) for common property forwarding
  • Sets Version to the latest version string before the guard (ensuring it's always initialized)
  • Guards with if (section is null || !section.Exists()) { return; } before binding
  • Binds non-version option properties from configuration
  • Marked [Experimental("SCME0002")]

C. public {Client}({Client}Settings settings) constructor

  • Delegates to the primary constructor via this(...) initializer
  • Extracts endpoint, non-auth required parameters, and options from settings
  • For API key auth: uses settings?.Credential?.Key != null ? new ApiKeyCredential(settings?.Credential?.Key) : null
  • For OAuth2 auth: uses settings?.CredentialProvider as AuthenticationTokenProvider
  • Marked [Experimental("SCME0002")]

Changes Made

  • ClientSettingsProvider.cs — new TypeProvider generating {Client}Settings; collects OtherRequiredParams (non-auth, non-endpoint required constructor parameters) and generates properties and BindCore bindings for them
  • ClientOptionsProvider.cs — adds IConfigurationSection constructor with version initialization before guard; adds default parameterless constructor when no API versions are present
  • ClientProvider.cs — adds settings constructor; passes non-auth required parameters in correct order using ?? default for value types
  • ScmOutputLibrary.cs — registers ClientSettingsProvider in the output
  • Packages.Data.props / .csproj — adds explicit Microsoft.Extensions.Configuration.Abstractions (v10.0.2) dependency
  • CSharpType.cs — removed FromExternalType; uses direct typeof(ClientSettings) with scoped #pragma warning disable SCME0002

Testing

  • 1170 tests passing
  • Generate.ps1 completes successfully; full solution builds with 0 errors
  • New tests for ClientSettingsProvider, ClientOptionsProvider IConfiguration constructor, and ClientProvider settings constructor
Original prompt

This section details on the original issue you should resolve

<issue_title>[.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors for clients</issue_title>
<issue_description>## Overview

Parent issue: Azure/azure-sdk-for-net#55491

The .NET generator should automatically produce IConfiguration-based client construction support for every generated client. This enables developers to configure clients using standard .NET configuration patterns (appsettings.json, environment variables) and register them with dependency injection containers.

Two services have been manually implemented as reference:

The generator should produce these automatically so every client gets configuration support without manual customization.

What the Generator Needs to Produce

Three artifacts per client:

A. {Client}Settings class

  • Extends ClientSettings (from System.ClientModel.Primitives)
  • Properties derived from the client's primary constructor parameters (excluding credential)
  • Implements BindCore(IConfigurationSection section) override
  • Marked [Experimental("SCME0002")]

B. internal {Client}Options(IConfigurationSection section) constructor

  • Calls base(section) — the base options class handles common properties (see Forwarding Binding)
  • Guards with if (section is null || !section.Exists()) { return; } before binding any properties
  • Binds each option-specific property from the section
  • Marked [Experimental("SCME0002")]

C. public {Client}({Client}Settings settings) constructor on the client

  • Delegates to the client's primary constructor (the one with the body implementation) — e.g., (AuthenticationPolicy, Options) or (Uri, AuthenticationPolicy, Options) depending on the client
  • Creates the authentication policy via AuthenticationPolicy.Create(settings) to pass to the primary constructor
  • Extracts other properties from settings and maps them to the primary constructor parameters (e.g., settings?.Endpoint, settings?.Options)
  • Not all clients have a URI parameter — the settings class properties mirror whatever the primary constructor requires
  • Marked [Experimental("SCME0002")]

How to Determine Settings Properties

The generator should inspect the client's primary public constructor (the one with the body implementation) parameters:

  • Endpoint/URI parameters (if present) → become Uri? properties on Settings (e.g., VaultUri, Endpoint)
  • Options parameter → becomes {Client}Options? property on Settings
  • Credential/AuthenticationPolicy parameter → handled by base ClientSettings.Credential / CredentialProvider, NOT duplicated
  • Any other non-credential constructor parameters may become settings properties

How to Implement BindCore

`csharp
protected override void BindCore(IConfigurationSection section)
{
if (section is null || !section.Exists())
{
return;
}

// String → use 'is string' pattern match
if (section["Endpoint"] is string endpoint)
{
    Endpoint = new Uri(endpoint);
}

// Options → GetSection + Exists check + internal ctor
IConfigurationSection optionsSection = section.GetSection("Options");
if (optionsSection.Exists())
{
    Options = new {Client}Options(optionsSection);
}

}
`

Key rule: If a configuration segment doesn't exist, bail early — don't set the property. No validation in BindCore. Let the client constructor that receives the settings do all required parameter validation (e.g., Argument.AssertNotNull).

Type Binding Patterns

The generator should use these patterns to bind properties from IConfigurationSection:

Type Pattern Example
string section[name] is string val TenantId = val
bool bool.TryParse(section[name], out bool val) DisableChallengeResourceVerification = val
Uri Uri.TryCreate(section[name], UriKind.Absolute, out Uri val) RedirectUri = val
TimeSpan TimeSpan.TryParse(section[name], out TimeSpan val) NetworkTimeout = val
int int.TryParse(section[name], out int val) MaxRetries = val
string[] / List<string> section.GetSection(name).GetChildren().Where(c => c.Value is not null).Select(c => c.Value!).ToList() AdditionallyAllowedTenants
Complex object section.GetSection(name) + .Exists() + new Type(section) BrowserCustomization = new BrowserCustomizationOptions(browserSection)
Custom struct/enum (extensible) new TypeName(section[name]) after null check Audience = new AppConfigurationAudience(audience)

For a comprehensive example of bin...


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits March 4, 2026 20:51
…onfiguration-enabled constructors

- Add new ClientSettingsProvider class that generates {Client}Settings classes
  - Extends ClientSettings from System.ClientModel.Primitives (future type)
  - Properties for endpoint (Uri?) and options ({Client}Options?)
  - BindCore override method binding from IConfigurationSection
  - Marked [Experimental("SCME0002")]
- Add IConfigurationSection constructor to ClientOptionsProvider
  - Internal constructor calling base(section)
  - Guards with null/Exists check
  - Binds non-version string properties from configuration
  - Marked [Experimental("SCME0002")]
- Add settings constructor to ClientProvider for root clients with configurable endpoints
  - Calls primary constructor via this() initializer
  - Passes endpoint, credential (if auth), and options from settings
  - Marked [Experimental("SCME0002")]
- Add ClientSettingsProvider output in ScmOutputLibrary.BuildClient
- Add CSharpType.FromExternalType() public factory method for types not in current NuGet
- Update tests to account for new constructors and generated code

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Settings feature

- Use HashSet for O(1) version property name lookup in BuildConfigurationSectionConstructor
- Rename local variable from 'propValue' suffix to 'FromConfig' for clarity
- Extract IsSettingsConstructor helper in test for maintainability

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI changed the title [WIP] Add auto-generation of ClientSettings class and IConfiguration constructors [.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors Mar 4, 2026
@microsoft-github-policy-service microsoft-github-policy-service bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Mar 4, 2026
private readonly InputEndpointParameter? _inputEndpointParam;

// ClientSettings base type - not yet in current NuGet package
internal static readonly CSharpType ClientSettingsType = CSharpType.FromExternalType("ClientSettings", "System.ClientModel.Primitives");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot we just need to upgrade to the version of System.ClientModel that has ClientSettings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 78afaca. System.ClientModel 1.9.0 (already the pinned version) does have ClientSettings in System.ClientModel.Primitives. Replaced the FromExternalType string-based workaround with typeof(ClientSettings) (with scoped #pragma warning disable SCME0002 since it's experimental) and typeof(IConfigurationSection). Also removed the FromExternalType method from CSharpType.cs since it's no longer needed.

@JoshLove-msft
Copy link
Contributor

@copilot run Generate.ps1 and investigate any failures.

…ClientModel 1.9.0 instead of string-based type reference

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Copilot AI and others added 2 commits March 5, 2026 04:04
…guard, fix API key credential in settings constructor, fix missing default ctor

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
… fix API key credential extraction, add default ctor, add package dep

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 5, 2026

@copilot run Generate.ps1 and investigate any failures.

Run complete in 04121e3. Generate.ps1 succeeded and the full solution builds with 0 errors. Fixed issues found:

  • Missing default constructor in ClientOptionsProvider when no API versions (suppressed the auto-generated one)
  • Invalid CredentialProvider as ApiKeyCredential cast (replaced with settings?.Credential?.Key != null ? new ApiKeyCredential(settings?.Credential?.Key) : null)
  • Missing non-auth required parameters in settings constructor (e.g. ClientType client, string serviceDeploymentVersion) — ClientSettingsProvider now collects and exposes OtherRequiredParams, generating properties and correct constructor args for them

…on constructor before guard

Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors for clients

2 participants