Skip to content
This repository was archived by the owner on Jun 16, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8717fbc
Put all optional client parameters into client options
pshao25 Nov 7, 2023
71287d1
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 7, 2023
4472b2f
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 8, 2023
c26032e
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 10, 2023
ab7d989
update
pshao25 Nov 13, 2023
4abe948
Regenerate all code (any successful run even without change will have…
actions-user Nov 13, 2023
15b9299
update
pshao25 Nov 14, 2023
f750175
Merge branch 'constructor3706' of https://github.com/pshao25/autorest…
pshao25 Nov 14, 2023
4997efc
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 14, 2023
3d9d590
update
pshao25 Nov 14, 2023
e2d833e
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 15, 2023
7aa23a5
update
pshao25 Nov 15, 2023
862d4eb
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 16, 2023
66beca9
update
pshao25 Nov 16, 2023
b303284
update
pshao25 Nov 16, 2023
37f52ba
update
pshao25 Nov 16, 2023
d9f06da
update
pshao25 Nov 16, 2023
87d5950
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 27, 2023
1506b29
update
pshao25 Nov 27, 2023
2c96f11
update
pshao25 Nov 27, 2023
c9f5a2c
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 27, 2023
b428cee
update
pshao25 Nov 27, 2023
9fabdbe
update
pshao25 Nov 28, 2023
e4d0ab7
Merge branch 'feature/v3' of https://github.com/Azure/autorest.csharp…
pshao25 Nov 28, 2023
e20e3b7
update
pshao25 Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using AutoRest.CSharp.Common.Input;
using AutoRest.CSharp.Output.Models.Types;
using AutoRest.CSharp.Utilities;

namespace AutoRest.CSharp.Generation.Writers
{
Expand Down Expand Up @@ -50,6 +51,21 @@ public static void WriteClientOptions(CodeWriter writer, ClientOptionsTypeProvid
}
}
}

if (clientOptions.AdditionalProperties != null && !Configuration.KeepOptionalClientParametersInConstructor)
{
if (clientOptions.ApiVersions is not null)
{
writer.Line();
}

foreach (var property in clientOptions.AdditionalProperties)
Comment thread
pshao25 marked this conversation as resolved.
Outdated
{
writer.WriteXmlDocumentationSummary(property.Description);
writer.Line($"public {property.Type} {property.Name.FirstCharToUpperCase()} {{ get; set; }}");
Comment thread
pshao25 marked this conversation as resolved.
Outdated
writer.Line();
}
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/AutoRest.CSharp/Common/Input/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using AutoRest.CSharp.AutoRest.Communication;
Expand Down Expand Up @@ -42,6 +43,7 @@ public static class Options
public const string UnreferencedTypesHandling = "unreferenced-types-handling";
public const string UseOverloadsBetweenProtocolAndConvenience = "use-overloads-between-protocol-and-convenience";
public const string KeepNonOverloadableProtocolSignature = "keep-non-overloadable-protocol-signature";
public const string KeepOptionalClientParametersInConstructor = "keep-optional-client-parameters-in-constructor";
public const string ModelFactoryForHlc = "model-factory-for-hlc";
public const string GenerateModelFactory = "generate-model-factory";
public const string ModelsToTreatEmptyStringAsNull = "models-to-treat-empty-string-as-null";
Expand Down Expand Up @@ -86,6 +88,7 @@ public static void Initialize(
UnreferencedTypesHandlingOption unreferencedTypesHandling,
bool useOverloadsBetweenProtocolAndConvenience,
bool keepNonOverloadableProtocolSignature,
bool keepOptionalClientParametersInConstructor,
string? projectFolder,
string? existingProjectFolder,
IReadOnlyList<string> protocolMethodList,
Expand Down Expand Up @@ -117,6 +120,7 @@ public static void Initialize(
UnreferencedTypesHandling = unreferencedTypesHandling;
UseOverloadsBetweenProtocolAndConvenience = useOverloadsBetweenProtocolAndConvenience;
KeepNonOverloadableProtocolSignature = keepNonOverloadableProtocolSignature;
KeepOptionalClientParametersInConstructor = keepOptionalClientParametersInConstructor;
ShouldTreatBase64AsBinaryData = !azureArm && !generation1ConvenienceClient ? shouldTreatBase64AsBinaryData : false;
UseCoreDataFactoryReplacements = useCoreDataFactoryReplacements;
projectFolder ??= ProjectFolderDefault;
Expand Down Expand Up @@ -264,6 +268,7 @@ internal static (string AbsoluteProjectFolder, string RelativeProjectFolder) Par
public static bool DeserializeNullCollectionAsNullValue { get; private set; }
public static bool UseOverloadsBetweenProtocolAndConvenience { get; private set; }
public static bool KeepNonOverloadableProtocolSignature { get; private set; }
public static bool KeepOptionalClientParametersInConstructor { get; private set; }

private static IReadOnlyList<string>? _oldModelFactoryEntries;
/// <summary>
Expand Down Expand Up @@ -318,6 +323,7 @@ public static void Initialize(IPluginCommunication autoRest, string defaultNames
unreferencedTypesHandling: GetOptionEnumValue<UnreferencedTypesHandlingOption>(autoRest, Options.UnreferencedTypesHandling),
useOverloadsBetweenProtocolAndConvenience: GetOptionBoolValue(autoRest, Options.UseOverloadsBetweenProtocolAndConvenience),
keepNonOverloadableProtocolSignature: GetOptionBoolValue(autoRest, Options.KeepNonOverloadableProtocolSignature),
keepOptionalClientParametersInConstructor: GetOptionBoolValue(autoRest, Options.KeepOptionalClientParametersInConstructor),
useCoreDataFactoryReplacements: GetOptionBoolValue(autoRest, Options.UseCoreDataFactoryReplacements),
projectFolder: GetProjectFolderOption(autoRest),
existingProjectFolder: autoRest.GetValue<string?>(Options.ExistingProjectfolder).GetAwaiter().GetResult(),
Expand Down Expand Up @@ -393,6 +399,8 @@ private static bool GetOptionBoolValue(IPluginCommunication autoRest, string opt
return true;
case Options.KeepNonOverloadableProtocolSignature:
return false;
case Options.KeepOptionalClientParametersInConstructor:
return false;
case Options.ShouldTreatBase64AsBinaryData:
return true;
case Options.DeserializeNullCollectionAsNullValue:
Expand Down Expand Up @@ -478,6 +486,7 @@ internal static void LoadConfiguration(JsonElement root, string? projectPath, st
ReadEnumOption<UnreferencedTypesHandlingOption>(root, Options.UnreferencedTypesHandling),
ReadOption(root, Options.UseOverloadsBetweenProtocolAndConvenience),
ReadOption(root, Options.KeepNonOverloadableProtocolSignature),
ReadOption(root, Options.KeepOptionalClientParametersInConstructor),
projectPath ?? ReadStringOption(root, Options.ProjectFolder),
existingProjectFolder,
protocolMethods,
Expand Down
2 changes: 2 additions & 0 deletions src/AutoRest.CSharp/Common/Output/Models/Shared/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal record Parameter(string Name, FormattableString? Description, CSharpTyp
{
public CSharpAttribute[] Attributes { get; init; } = Array.Empty<CSharpAttribute>();
public bool IsOptionalInSignature => DefaultValue != null;
public bool IsEndpoint => Type.Equals(typeof(Uri)) && Name == KnownParameters.Endpoint.Name;
Comment thread
pshao25 marked this conversation as resolved.
Outdated

public Parameter ToRequired()
{
Expand Down Expand Up @@ -82,6 +83,7 @@ public static Parameter FromInputParameter(in InputParameter operationParameter,

private static Constant? GetDefaultValue(InputParameter operationParameter, TypeFactory typeFactory) => operationParameter switch
{
{ Name: "$host", DefaultValue.Value: ""} => (Constant?)null, // In M4, when endpoint is not set, its default value is an empty string instead of null
Comment thread
pshao25 marked this conversation as resolved.
Outdated
{ NameInRequest: var nameInRequest } when RequestHeader.ClientRequestIdHeaders.Contains(nameInRequest) => Constant.FromExpression($"message.{Configuration.ApiTypes.HttpMessageRequestName}.ClientRequestId", new CSharpType(typeof(string))),
{ NameInRequest: var nameInRequest } when RequestHeader.ReturnClientRequestIdResponseHeaders.Contains(nameInRequest) => new Constant("true", new CSharpType(typeof(string))),
{ DefaultValue: not null } => BuilderHelpers.ParseConstant(operationParameter.DefaultValue.Value, typeFactory.CreateType(operationParameter.DefaultValue.Type)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Text;
using AutoRest.CSharp.Input.Source;
using AutoRest.CSharp.Output.Models.Shared;

namespace AutoRest.CSharp.Output.Models.Types
{
Expand All @@ -16,6 +17,7 @@ internal sealed class ClientOptionsTypeProvider : TypeProvider

public FormattableString Description { get; }
public IReadOnlyList<ApiVersion>? ApiVersions { get; }
public IReadOnlyList<Parameter>? AdditionalProperties { get; init; }
Comment thread
pshao25 marked this conversation as resolved.
Outdated
protected override string DefaultName { get; }
protected override string DefaultAccessibility { get; }

Expand Down
4 changes: 4 additions & 0 deletions src/AutoRest.CSharp/LowLevel/Generation/DpgClientWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ private void WritePrimaryPublicConstructor(ConstructorSignature signature)
{
_writer.Line($"{field.Name:I} = {clientOptionsParameter.Name:I}.Version;");
}
else if (parameter.IsOptionalInSignature && !parameter.IsEndpoint && !Configuration.KeepOptionalClientParametersInConstructor)
Comment thread
pshao25 marked this conversation as resolved.
Outdated
{
_writer.Line($"{field.Name:I} = {clientOptionsParameter.Name:I}.{parameter.Name.FirstCharToUpperCase()};");
}
else
{
_writer.Line($"{field.Name:I} = {parameter.Name:I};");
Expand Down
23 changes: 15 additions & 8 deletions src/AutoRest.CSharp/LowLevel/Output/DpgOutputLibraryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using AutoRest.CSharp.Generation.Types;
using AutoRest.CSharp.Input.Source;
using AutoRest.CSharp.Output.Builders;
using AutoRest.CSharp.Output.Models.Shared;
using AutoRest.CSharp.Output.Models.Types;
using AutoRest.CSharp.Utilities;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -44,7 +45,8 @@ public DpgOutputLibrary Build(bool isTspInput)
.ToDictionary(ci => ci.Name);
AssignParentClients(inputClients, clientInfosByName);
var topLevelClientInfos = SetHierarchy(clientInfosByName);
var clientOptions = CreateClientOptions(topLevelClientInfos);
var parametersInClientOptions = new List<Parameter>();
var clientOptions = CreateClientOptions(topLevelClientInfos, parametersInClientOptions);

SetRequestsToClients(clientInfosByName.Values);

Expand All @@ -59,7 +61,7 @@ public DpgOutputLibrary Build(bool isTspInput)
CreateModels(models, library.TypeFactory);
CreateEnums(enums, models, library.TypeFactory);
}
CreateClients(clients, topLevelClientInfos, library.TypeFactory, clientOptions);
CreateClients(clients, topLevelClientInfos, library.TypeFactory, clientOptions, parametersInClientOptions);

return library;
}
Expand Down Expand Up @@ -459,7 +461,7 @@ private static IReadOnlyList<InputParameter> UpdateOperationParameters(IReadOnly
return parameters;
}

private ClientOptionsTypeProvider CreateClientOptions(IReadOnlyList<ClientInfo> topLevelClientInfos)
private ClientOptionsTypeProvider CreateClientOptions(IReadOnlyList<ClientInfo> topLevelClientInfos, List<Parameter> parametersInClientOptions)
{
var clientName = topLevelClientInfos.Count == 1
? topLevelClientInfos[0].Name
Expand All @@ -477,7 +479,10 @@ private ClientOptionsTypeProvider CreateClientOptions(IReadOnlyList<ClientInfo>
throw new InvalidOperationException("Multiple API versions are not supported in the unbranded path.");
apiVersions = null;
}
return new ClientOptionsTypeProvider(apiVersions, clientOptionsName, _defaultNamespace, description, _sourceInputModel);
return new ClientOptionsTypeProvider(apiVersions, clientOptionsName, _defaultNamespace, description, _sourceInputModel)
{
AdditionalProperties = parametersInClientOptions
};
}

private static ClientInfo CreateClientInfo(InputClient ns, SourceInputModel? sourceInputModel, string rootNamespaceName)
Expand Down Expand Up @@ -626,9 +631,9 @@ private static void SetRequestToClient(ClientInfo clientInfo, InputOperation ope
clientInfo.Requests.Add(operation);
}

private void CreateClients(List<LowLevelClient> allClients, IEnumerable<ClientInfo> topLevelClientInfos, TypeFactory typeFactory, ClientOptionsTypeProvider clientOptions)
private void CreateClients(List<LowLevelClient> allClients, IEnumerable<ClientInfo> topLevelClientInfos, TypeFactory typeFactory, ClientOptionsTypeProvider clientOptions, List<Parameter> parametersInClientOptions)
{
var topLevelClients = CreateClients(topLevelClientInfos, typeFactory, clientOptions, null);
var topLevelClients = CreateClients(topLevelClientInfos, typeFactory, clientOptions, null, parametersInClientOptions);

// Simple implementation of breadth first traversal
allClients.AddRange(topLevelClients);
Expand All @@ -638,7 +643,7 @@ private void CreateClients(List<LowLevelClient> allClients, IEnumerable<ClientIn
}
}

private IEnumerable<LowLevelClient> CreateClients(IEnumerable<ClientInfo> clientInfos, TypeFactory typeFactory, ClientOptionsTypeProvider clientOptions, LowLevelClient? parentClient)
private IEnumerable<LowLevelClient> CreateClients(IEnumerable<ClientInfo> clientInfos, TypeFactory typeFactory, ClientOptionsTypeProvider clientOptions, LowLevelClient? parentClient, List<Parameter> parametersInClientOptions)
{
foreach (var clientInfo in clientInfos)
{
Expand Down Expand Up @@ -673,7 +678,9 @@ private IEnumerable<LowLevelClient> CreateClients(IEnumerable<ClientInfo> client
SubClients = subClients
};

subClients.AddRange(CreateClients(clientInfo.Children, typeFactory, clientOptions, client));
subClients.AddRange(CreateClients(clientInfo.Children, typeFactory, clientOptions, client, parametersInClientOptions));
// parametersInClientOptions is assigned to ClientOptionsTypeProvider.AdditionalProperties before, which makes sure AdditionalProperties is readonly and won't change after ClientOptionsTypeProvider is built.
parametersInClientOptions.AddRange(client.GetOptionalParametersInOptions());
Comment thread
pshao25 marked this conversation as resolved.

yield return client;
}
Expand Down
13 changes: 12 additions & 1 deletion src/AutoRest.CSharp/LowLevel/Output/LowLevelClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public static IEnumerable<LowLevelClientMethod> BuildMethods(LowLevelClient? cli
if (!IsSubClient)
{
var requiredParameters = RestClientBuilder.GetRequiredParameters(orderedParameters).ToArray();
var optionalParameters = RestClientBuilder.GetOptionalParameters(orderedParameters).Append(CreateOptionsParameter()).ToArray();
var optionalParameters = GetOptionalParametersInConstructor(RestClientBuilder.GetOptionalParameters(orderedParameters).Append(CreateOptionsParameter())).ToArray();

return (
BuildPrimaryConstructors(requiredParameters, optionalParameters).ToArray(),
Expand All @@ -153,6 +153,17 @@ public static IEnumerable<LowLevelClientMethod> BuildMethods(LowLevelClient? cli
}
}

private IEnumerable<Parameter> GetOptionalParametersInConstructor(IEnumerable<Parameter> optionalParameters)
{
return Configuration.KeepOptionalClientParametersInConstructor? optionalParameters : optionalParameters.Where(
p => ClientOptions.Type.EqualsIgnoreNullable(p.Type) || p.IsEndpoint); // Endpoint is an exception, even it is optional, still need to be the parameter of constructor
}

public IEnumerable<Parameter> GetOptionalParametersInOptions()
{
return RestClientBuilder.GetOptionalParameters(Parameters).Where(p => !p.IsEndpoint);
}

private IEnumerable<ConstructorSignature> BuildPrimaryConstructors(IReadOnlyList<Parameter> requiredParameters, IReadOnlyList<Parameter> optionalParameters)
{
var optionalToRequired = optionalParameters
Expand Down
2 changes: 2 additions & 0 deletions src/TypeSpec.Extension/Emitter.Csharp/src/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
options["use-overloads-between-protocol-and-convenience"],
"keep-non-overloadable-protocol-signature":
options["keep-non-overloadable-protocol-signature"],
"keep-optional-client-parameters-in-constructor":
options["keep-optional-client-parameters-in-constructor"],
"model-namespace": options["model-namespace"],
"models-to-treat-empty-string-as-null":
options["models-to-treat-empty-string-as-null"],
Expand Down
5 changes: 5 additions & 0 deletions src/TypeSpec.Extension/Emitter.Csharp/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type NetEmitterOptions = {
"existing-project-folder"?: string;
"use-overloads-between-protocol-and-convenience"?: boolean;
"keep-non-overloadable-protocol-signature"?: boolean;
"keep-optional-client-parameters-in-constructor"?: boolean;
debug?: boolean;
"models-to-treat-empty-string-as-null"?: string[];
"additional-intrinsic-types-to-treat-empty-string-as-null"?: string[];
Expand Down Expand Up @@ -72,6 +73,10 @@ export const NetEmitterOptionsSchema: JSONSchemaType<NetEmitterOptions> = {
type: "boolean",
nullable: true
},
"keep-optional-client-parameters-in-constructor": {
type: "boolean",
nullable: true
},
debug: { type: "boolean", nullable: true },
"models-to-treat-empty-string-as-null": {
type: "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public void Method(int? nullableInt, List<int> intList, List<int?> nullableIntLi
unreferencedTypesHandling: Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize,
useOverloadsBetweenProtocolAndConvenience: true,
keepNonOverloadableProtocolSignature: false,
keepOptionalClientParametersInConstructor: false,
projectFolder: "/..",
existingProjectFolder: null,
protocolMethodList: Array.Empty<string>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public void Setup()
unreferencedTypesHandling: Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize,
useOverloadsBetweenProtocolAndConvenience: true,
keepNonOverloadableProtocolSignature: false,
keepOptionalClientParametersInConstructor: false,
useCoreDataFactoryReplacements: true,
projectFolder: "/..",
existingProjectFolder: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public void Initialize()
unreferencedTypesHandling: Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize,
useOverloadsBetweenProtocolAndConvenience: true,
keepNonOverloadableProtocolSignature: false,
keepOptionalClientParametersInConstructor: false,
projectFolder: ".",
existingProjectFolder: null,
protocolMethodList: Array.Empty<string>(),
Expand Down
Loading