[.NET Generator] Auto-generate ClientSettings class and IConfiguration-enabled constructors#9920
Conversation
…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 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>
…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>
Run complete in 04121e3. Generate.ps1 succeeded and the full solution builds with 0 errors. Fixed issues found:
|
…on constructor before guard Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
|
ompilation completed successfully. Building http/client/structure/client-operation-group
Build FAILED. /mnt/vss/_work/1/s/packages/http-client-csharp/generator/TestProjects/Spector/http/client/structure/client-operation-group/src/Generated/SubNamespaceSecondClientSettings.cs(36,30): error CS1729: 'ClientType' does not contain a constructor that takes 1 arguments [/mnt/vss/_work/1/s/packages/http-client-csharp/generator/TestProjects/Spector/http/client/structure/client-operation-group/src/Client.Structure.Service.csproj::TargetFramework=net8.0] |
…Core Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Fixed in 51fbd66. The build failure was caused by generating |
|
@copilot what about complex objects? Did we add handling and test cases for those? |
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Added in 60a3de0. Complex objects now use the |
@copilot do we handle complex object properties on the ClientOptions? This last commit added handling for ctor parameters, but what about ClientOption properties? |
…uctor Refactored binding helper methods in ClientSettingsProvider to be internal static and reusable. ClientOptionsProvider now uses AppendBindingForProperty for type-aware binding of all property types (string, bool, int, TimeSpan, Uri, List<string>, extensible/fixed enums, complex objects) instead of treating all properties as strings. Added tests for bool, int, string, extensible enum, fixed enum, and complex object property bindings in ClientOptionsProviderTests. Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Yes, handled in ca2320b. Refactored the binding helper methods in Added 6 new tests for ClientOptions properties: |
… numeric types Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
…nual VariableExpression Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Co-authored-by: JoshLove-msft <102122018+JoshLove-msft@users.noreply.github.com>
… in ClientSettingsProvider Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
ClientSettingsProvider.cs- new TypeProvider generating{Client}Settingsclass extendingClientSettingsClientOptionsProvider.cs- addinternal {Client}Options(IConfigurationSection section)constructor with type-aware property bindingClientProvider.cs- addpublic {Client}({Client}Settings settings)constructor and internal(AuthenticationPolicy?, endpoint, options)implementation constructorScmOutputLibrary.cs- registerClientSettingsProviderin the output_flowsis nowstatic readonly, useBindingFlags.StaticandGetValue(null)instead ofBindingFlags.InstanceCredentialParamNameandSettingsParamNameconstants inClientProvider.csfor consistencyClientSettingsProvider.BindCore():string,bool,int,TimeSpan(TryParse),Uri(TryCreate),List<string>(GetSection/GetChildren/Where/Select/ToList), extensible enums (new TypeName(val)), fixed enums (Enum.TryParse), and complex objects (GetSection + Exists + new Type(section))string,bool,int,TimeSpan,Uri,List<string>, extensible enum, fixed enum, complex object) and multi-type property scenariosClientType) now useEnum.TryParseinstead ofnew TypeName(val)constructorinternal staticmethods onClientSettingsProviderfor reuse by bothClientSettingsProviderandClientOptionsProviderClientOptionsIConfigurationSection constructor — properties now use correct binding patterns (bool.TryParse,int.TryParse,TimeSpan.TryParse,Uri.TryCreate,List<string>, extensible/fixed enums, complex objects) instead of treating all properties as stringsIsNotsnippet toValueExpressionandParameterProviderforis notpattern expression support, used inClientSettingsProviderstring list bindingOriginal 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}SettingsclassClientSettings(fromSystem.ClientModel.Primitives)BindCore(IConfigurationSection section)override[Experimental("SCME0002")]B.
internal {Client}Options(IConfigurationSection section)constructorbase(section)— the base options class handles common properties (see Forwarding Binding)if (section is null || !section.Exists()) { return; }before binding any properties[Experimental("SCME0002")]C.
public {Client}({Client}Settings settings)constructor on the client(AuthenticationPolicy, Options)or(Uri, AuthenticationPolicy, Options)depending on the clientAuthenticationPolicy.Create(settings)to pass to the primary constructorsettings?.Endpoint,settings?.Options)[Experimental("SCME0002")]How to Determine Settings Properties
The generator should inspect the client's primary public constructor (the one with the body implementation) parameters:
Uri?properties on Settings (e.g.,VaultUri,Endpoint){Client}Options?property on SettingsClientSettings.Credential/CredentialProvider, NOT duplicatedHow to Implement BindCore
`csharp
protected override void BindCore(IConfigurationSection section)
{
if (section is null || !section.Exists())
{
return;
}
}
`
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:stringsection[name] is string valTenantId = valboolbool.TryParse(section[name], out bool val)DisableChallengeResourceVerification = valUriUri.TryCreate(section[name], UriKind.Absolute, out Uri val)RedirectUri = valTimeSpanTimeSpan.TryParse(section[name], out TimeSpan val)NetworkTimeout = valintint.TryParse(section[name], out int val)MaxRetries = valstring[]/List<string>section.GetSection(name).GetChildren().Where(c => c.Value is not null).Select(c => c.Value!).ToList()AdditionallyAllowedTenantssection.GetSection(name)+.Exists()+new Type(section)BrowserCustomization = new BrowserCustomizationOptions(browserSection)new TypeName(section[name])after null checkAudience = 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.