Skip to content

Commit 115912f

Browse files
Fix subclient initialization (#9128)
1 parent c6c17ee commit 115912f

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ void AppendConstructors(
500500
var constructorModifier = onlyContainsUnsupportedAuth ? MethodSignatureModifiers.Internal : MethodSignatureModifiers.Public;
501501
var primaryConstructor = new ConstructorProvider(
502502
new ConstructorSignature(Type, _publicCtorDescription, constructorModifier, primaryConstructorParameters),
503-
BuildPrimaryConstructorBody(primaryConstructorParameters, authFields),
503+
BuildPrimaryConstructorBody(primaryConstructorParameters, authFields, ClientOptions, ClientOptionsParameter),
504504
this);
505505

506506
primaryConstructors.Add(primaryConstructor);
@@ -564,7 +564,8 @@ void AppendSubClientPublicConstructorsForAuth(
564564
// - client options parameter (we need to get this from the root client)
565565
var rootClient = GetRootClient();
566566
var clientOptionsParameter = rootClient?.ClientOptionsParameter;
567-
if (clientOptionsParameter == null)
567+
var clientOptionsProvider = rootClient?.ClientOptions;
568+
if (clientOptionsParameter == null || clientOptionsProvider == null)
568569
{
569570
// Cannot create public constructor without client options
570571
return;
@@ -574,7 +575,7 @@ void AppendSubClientPublicConstructorsForAuth(
574575
ParameterProvider[] primaryConstructorParameters = [_endpointParameter, .. requiredParameters, clientOptionsParameter];
575576
var primaryConstructor = new ConstructorProvider(
576577
new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Public, primaryConstructorParameters),
577-
BuildPrimaryConstructorBody(primaryConstructorParameters, authFields),
578+
BuildPrimaryConstructorBody(primaryConstructorParameters, authFields, clientOptionsProvider, clientOptionsParameter),
578579
this);
579580

580581
primaryConstructors.Add(primaryConstructor);
@@ -647,9 +648,9 @@ private IReadOnlyList<ParameterProvider> GetRequiredParameters(FieldProvider? au
647648
return param;
648649
}
649650

650-
private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<ParameterProvider> primaryConstructorParameters, AuthFields? authFields)
651+
private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<ParameterProvider> primaryConstructorParameters, AuthFields? authFields, ClientOptionsProvider? clientOptionsProvider, ParameterProvider? clientOptionsParameter)
651652
{
652-
if (ClientOptions is null || ClientOptionsParameter is null)
653+
if (clientOptionsProvider is null || clientOptionsParameter is null)
653654
{
654655
return [MethodBodyStatement.Empty];
655656
}
@@ -666,7 +667,7 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<Paramete
666667
endpointAssignment = EndpointField.Assign(_endpointParameter);
667668
}
668669
List<MethodBodyStatement> body = [
669-
ClientOptionsParameter.Assign(ClientOptionsParameter.InitializationValue!, nullCoalesce: true).Terminate(),
670+
clientOptionsParameter.Assign(clientOptionsParameter.InitializationValue!, nullCoalesce: true).Terminate(),
670671
MethodBodyStatement.EmptyLine,
671672
endpointAssignment.Terminate()
672673
];
@@ -706,14 +707,14 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<Paramete
706707
break;
707708
}
708709

709-
body.Add(PipelineProperty.Assign(This.ToApi<ClientPipelineApi>().Create(ClientOptionsParameter, perRetryPolicies)).Terminate());
710+
body.Add(PipelineProperty.Assign(This.ToApi<ClientPipelineApi>().Create(clientOptionsParameter, perRetryPolicies)).Terminate());
710711

711-
var clientOptionsPropertyDict = ClientOptions.Properties.ToDictionary(p => p.Name.ToIdentifierName());
712+
var clientOptionsPropertyDict = clientOptionsProvider.Properties.ToDictionary(p => p.Name.ToIdentifierName());
712713
foreach (var f in Fields)
713714
{
714-
if (f == _apiVersionField && ClientOptions.VersionProperty != null)
715+
if (f == _apiVersionField && clientOptionsProvider.VersionProperty != null)
715716
{
716-
body.Add(f.Assign(ClientOptionsParameter.Property(ClientOptions.VersionProperty.Name)).Terminate());
717+
body.Add(f.Assign(clientOptionsParameter.Property(clientOptionsProvider.VersionProperty.Name)).Terminate());
717718
}
718719
else if (clientOptionsPropertyDict.TryGetValue(f.Name.ToIdentifierName(), out var optionsProperty))
719720
{

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,19 @@ public void TestBuildConstructors_ForSubClient_InitializedByIndividually_HasPubl
607607
c => c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToList();
608608
Assert.IsTrue(publicConstructors.Count > 0, "SubClient with InitializedBy.Individually should have public constructors");
609609

610+
// primary constructor should set the pipeline, options, and endpoint
611+
var primaryConstructor = publicConstructors.FirstOrDefault(
612+
c => c.Signature?.Initializer == null);
613+
Assert.IsNotNull(primaryConstructor, "SubClient with InitializedBy.Individually should have primary public constructor");
614+
StringAssert.Contains(
615+
"options ??= new global::Sample.ParentClientOptions();",
616+
primaryConstructor!.BodyStatements!.ToDisplayString(),
617+
"Primary constructor should null coalesce options parameter");
618+
StringAssert.Contains(
619+
"Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty<global::System.ClientModel.Primitives.PipelinePolicy>(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.SubClient).Assembly) }, Array.Empty<global::System.ClientModel.Primitives.PipelinePolicy>());",
620+
primaryConstructor.BodyStatements!.ToDisplayString(),
621+
"Primary constructor should set the Pipeline property");
622+
610623
// Should NOT have internal constructor since InitializedBy does not include Parent
611624
var internalConstructor = constructors.FirstOrDefault(
612625
c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal);
@@ -674,6 +687,19 @@ public void TestBuildConstructors_ForSubClient_InitializedByBoth_HasBothConstruc
674687
c => c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToList();
675688
Assert.IsTrue(publicConstructors.Count > 0, "SubClient with InitializedBy.Individually | Parent should have public constructors");
676689

690+
// primary constructor should set the pipeline, options, and endpoint
691+
var primaryConstructor = publicConstructors.FirstOrDefault(
692+
c => c.Signature?.Initializer == null);
693+
Assert.IsNotNull(primaryConstructor, "SubClient with InitializedBy.Individually should have primary public constructor");
694+
StringAssert.Contains(
695+
"options ??= new global::Sample.ParentClientOptions();",
696+
primaryConstructor!.BodyStatements!.ToDisplayString(),
697+
"Primary constructor should null coalesce options parameter");
698+
StringAssert.Contains(
699+
"Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty<global::System.ClientModel.Primitives.PipelinePolicy>(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.SubClient).Assembly) }, Array.Empty<global::System.ClientModel.Primitives.PipelinePolicy>());",
700+
primaryConstructor.BodyStatements!.ToDisplayString(),
701+
"Primary constructor should set the Pipeline property");
702+
677703
// Should also have internal constructor
678704
var internalConstructor = constructors.FirstOrDefault(
679705
c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal);

packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Metrics.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public Metrics(Uri endpoint, SampleTypeSpecClientOptions options)
4747
{
4848
Argument.AssertNotNull(endpoint, nameof(endpoint));
4949

50+
options ??= new SampleTypeSpecClientOptions();
51+
52+
_endpoint = endpoint;
53+
Pipeline = ClientPipeline.Create(options, Array.Empty<PipelinePolicy>(), new PipelinePolicy[] { new UserAgentPolicy(typeof(Metrics).Assembly) }, Array.Empty<PipelinePolicy>());
5054
}
5155

5256
/// <summary> The HTTP pipeline for sending and receiving REST requests and responses. </summary>

0 commit comments

Comments
 (0)