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 10 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 IList<Parameter>? AdditionalProperties { get; private set; }
Comment thread
pshao25 marked this conversation as resolved.
Outdated
protected override string DefaultName { get; }
protected override string DefaultAccessibility { get; }

Expand All @@ -29,6 +31,18 @@ public ClientOptionsTypeProvider(IReadOnlyList<string>? versions, string name, s
ApiVersions = ConvertApiVersions(versions);
}

public void AddAdditionalProperty(IEnumerable<Parameter> parameters)
{
AdditionalProperties ??= new List<Parameter>();
foreach (var parameter in parameters)
{
if (!AdditionalProperties.Any(property => property.Name == parameter.Name))
{
AdditionalProperties.Add(parameter);
}
}
}

private static ApiVersion[] ConvertApiVersions(IReadOnlyList<string> versions) =>
versions.Select((v, i) => new ApiVersion(NormalizeVersion(v), $"Service version \"{v}\"", i + 1, v)).ToArray();

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 @@ -252,6 +252,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
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,8 @@ private IEnumerable<LowLevelClient> CreateClients(IEnumerable<ClientInfo> client

subClients.AddRange(CreateClients(clientInfo.Children, typeFactory, clientOptions, client));

clientOptions.AddAdditionalProperty(client.GetOptionalParametersInOptions());
Comment thread
pshao25 marked this conversation as resolved.
Outdated

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
71 changes: 42 additions & 29 deletions test/AutoRest.TestServerLowLevel.Tests/url-path-items.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,68 @@ public class UrlPathItemsTests : TestServerLowLevelTestBase
{
[Test]
public Task UrlPathItemGetAll() => TestStatus(async (host) =>
await new PathItemsClient(globalStringPath: "globalStringPath",
globalStringQuery: "globalStringQuery",
{
var options = new AutoRestUrlTestServiceClientOptions();
options.GlobalStringQuery = "globalStringQuery";
Comment thread
pshao25 marked this conversation as resolved.
Outdated
return await new PathItemsClient(globalStringPath: "globalStringPath",
credential: Key,
endpoint: host,
options: null)
options: options)
.GetAllWithValuesAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: "pathItemStringQuery",
localStringPath: "localStringPath",
localStringQuery: "localStringQuery"));
localStringQuery: "localStringQuery");
});

[Test]
public Task UrlPathItemGetPathItemAndLocalNull() => TestStatus(async (host) =>
await new PathItemsClient(globalStringPath: "globalStringPath",
globalStringQuery: "globalStringQuery",
{
var options = new AutoRestUrlTestServiceClientOptions();
options.GlobalStringQuery = "globalStringQuery";
return await new PathItemsClient(globalStringPath: "globalStringPath",
credential: Key,
endpoint: host,
options: null)
options: options)
.GetLocalPathItemQueryNullAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: null,
localStringPath: "localStringPath",
localStringQuery: null));
localStringQuery: null);
});


[Test]
public Task UrlPathItemGetGlobalNull() => TestStatus(async (host) =>
await new PathItemsClient(globalStringPath: "globalStringPath",
endpoint: host,
credential: Key,
globalStringQuery: null,
options: null)
.GetGlobalQueryNullAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: "pathItemStringQuery",
localStringPath: "localStringPath",
localStringQuery: "localStringQuery"));
{
var options = new AutoRestUrlTestServiceClientOptions();
options.GlobalStringQuery = null;
return await new PathItemsClient(globalStringPath: "globalStringPath",
endpoint: host,
credential: Key,
options: options)
.GetGlobalQueryNullAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: "pathItemStringQuery",
localStringPath: "localStringPath",
localStringQuery: "localStringQuery");
});

[Test]
public Task UrlPathItemGetGlobalAndLocalNull() => TestStatus(async (host) =>
await new PathItemsClient(
globalStringPath: "globalStringPath",
endpoint: host,
credential: Key,
globalStringQuery: null,
options: null)
.GetGlobalAndLocalQueryNullAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: "pathItemStringQuery",
localStringPath: "localStringPath",
localStringQuery: null));
{
var options = new AutoRestUrlTestServiceClientOptions();
options.GlobalStringQuery = null;
return await new PathItemsClient(
globalStringPath: "globalStringPath",
endpoint: host,
credential: Key,
options: options)
.GetGlobalAndLocalQueryNullAsync(
pathItemStringPath: "pathItemStringPath",
pathItemStringQuery: "pathItemStringQuery",
localStringPath: "localStringPath",
localStringQuery: null);
});
}
}
4 changes: 2 additions & 2 deletions test/TestProjects/ApiVersion/Generated/ApiVersionClient.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading