diff --git a/packages/http-client-csharp/emitter/src/lib/client-converter.ts b/packages/http-client-csharp/emitter/src/lib/client-converter.ts index 0099b5331ae..8ecd2783345 100644 --- a/packages/http-client-csharp/emitter/src/lib/client-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/client-converter.ts @@ -21,6 +21,7 @@ import { import { fromMethodParameter, fromSdkServiceMethod, + getCorrespondingMethodParams, getParameterDefaultValue, } from "./operation-converter.js"; import { fromSdkType } from "./type-converter.js"; @@ -182,6 +183,7 @@ function fromSdkClient( skipUrlEncoding: false, readOnly: isReadOnly(parameter), crossLanguageDefinitionId: parameter.crossLanguageDefinitionId, + correspondingMethodParams: getCorrespondingMethodParams(sdkContext, parameter), }); } return parameters; diff --git a/packages/http-client-csharp/emitter/src/lib/operation-converter.ts b/packages/http-client-csharp/emitter/src/lib/operation-converter.ts index bada9905120..618cfdbfbbe 100644 --- a/packages/http-client-csharp/emitter/src/lib/operation-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/operation-converter.ts @@ -441,6 +441,7 @@ function fromQueryParameter( decorators: p.decorators, crossLanguageDefinitionId: p.crossLanguageDefinitionId, readOnly: isReadOnly(p), + correspondingMethodParams: getCorrespondingMethodParams(sdkContext, p), }; sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar); @@ -472,6 +473,7 @@ function fromPathParameter( decorators: p.decorators, readOnly: isReadOnly(p), crossLanguageDefinitionId: p.crossLanguageDefinitionId, + correspondingMethodParams: getCorrespondingMethodParams(sdkContext, p), }; sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar); @@ -502,6 +504,7 @@ function fromHeaderParameter( readOnly: isReadOnly(p), decorators: p.decorators, crossLanguageDefinitionId: p.crossLanguageDefinitionId, + correspondingMethodParams: getCorrespondingMethodParams(sdkContext, p), }; sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar); @@ -530,6 +533,7 @@ function fromBodyParameter( decorators: p.decorators, readOnly: isReadOnly(p), crossLanguageDefinitionId: p.crossLanguageDefinitionId, + correspondingMethodParams: getCorrespondingMethodParams(sdkContext, p), }; sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar); @@ -920,6 +924,30 @@ function getArraySerializationDelimiter( return format ? collectionFormatToDelimMap[format] : undefined; } +export function getCorrespondingMethodParams( + sdkContext: CSharpEmitterContext, + p: SdkHttpParameter | SdkModelPropertyType, +): InputMethodParameter[] | undefined { + // methodParameterSegments is a 2D array where each segment array represents a path to a method parameter + // We need to get the last element of each segment array which is the actual method parameter + const methodParameterSegments = (p as any).methodParameterSegments; + if (!methodParameterSegments || methodParameterSegments.length === 0) { + return undefined; + } + + const namespace = getClientNamespaceString(sdkContext) ?? ""; + const methodParams: InputMethodParameter[] = []; + + for (const segments of methodParameterSegments) { + if (segments && segments.length > 0) { + const methodParam = segments[segments.length - 1] as SdkMethodParameter; + methodParams.push(fromMethodParameter(sdkContext, methodParam, namespace)); + } + } + + return methodParams.length > 0 ? methodParams : undefined; +} + function getResponseType( sdkContext: CSharpEmitterContext, type: SdkType | undefined, diff --git a/packages/http-client-csharp/emitter/src/type/input-type.ts b/packages/http-client-csharp/emitter/src/type/input-type.ts index b4008677dd8..d031071ad65 100644 --- a/packages/http-client-csharp/emitter/src/type/input-type.ts +++ b/packages/http-client-csharp/emitter/src/type/input-type.ts @@ -207,6 +207,7 @@ export interface InputQueryParameter extends InputPropertyTypeBase { explode: boolean; scope: InputParameterScope; serializedName: string; + correspondingMethodParams?: InputMethodParameter[]; } export interface InputPathParameter extends InputPropertyTypeBase { @@ -218,6 +219,7 @@ export interface InputPathParameter extends InputPropertyTypeBase { serverUrlTemplate?: string; scope: InputParameterScope; serializedName: string; + correspondingMethodParams?: InputMethodParameter[]; } export interface InputHeaderParameter extends InputPropertyTypeBase { @@ -227,6 +229,7 @@ export interface InputHeaderParameter extends InputPropertyTypeBase { isContentType: boolean; scope: InputParameterScope; serializedName: string; + correspondingMethodParams?: InputMethodParameter[]; } export interface InputBodyParameter extends InputPropertyTypeBase { @@ -235,6 +238,7 @@ export interface InputBodyParameter extends InputPropertyTypeBase { defaultContentType: string; scope: InputParameterScope; serializedName: string; + correspondingMethodParams?: InputMethodParameter[]; } export interface InputEndpointParameter extends InputPropertyTypeBase { @@ -244,6 +248,7 @@ export interface InputEndpointParameter extends InputPropertyTypeBase { scope: InputParameterScope; serializedName: string; isEndpoint: boolean; + correspondingMethodParams?: InputMethodParameter[]; } export interface InputEnumType extends InputTypeBase { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputParameter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputParameter.cs index 1dfd9e14a5c..0784239a1e4 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputParameter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputParameter.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.Text.Json; namespace Microsoft.TypeSpec.Generator.Input @@ -26,6 +27,7 @@ protected InputParameter( } public InputParameterScope Scope { get; internal set; } + public IReadOnlyList? CorrespondingMethodParams { get; internal set; } /// /// Update the instance with given parameters. diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputBodyParameterConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputBodyParameterConverter.cs index f2eae76bd38..452c0b49e44 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputBodyParameterConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputBodyParameterConverter.cs @@ -62,6 +62,7 @@ internal static InputBodyParameter ReadInputBodyParameter(ref Utf8JsonReader rea IReadOnlyList? contentTypes = null; string? defaultContentType = null; IReadOnlyList? decorators = null; + IReadOnlyList? correspondingMethodParams = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -79,7 +80,8 @@ internal static InputBodyParameter ReadInputBodyParameter(ref Utf8JsonReader rea || reader.TryReadString("scope", ref scope) || reader.TryReadComplexType("contentTypes",options, ref contentTypes) || reader.TryReadComplexType("defaultContentType", options, ref defaultContentType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("correspondingMethodParams", options, ref correspondingMethodParams); if (!isKnownProperty) { @@ -101,6 +103,7 @@ internal static InputBodyParameter ReadInputBodyParameter(ref Utf8JsonReader rea parameter.Scope = InputParameter.ParseScope(type, name, scope); parameter.ContentTypes = contentTypes ?? throw new JsonException($"{nameof(InputBodyParameter)} must have a contentTypes."); parameter.DefaultContentType = defaultContentType ?? throw new JsonException($"{nameof(InputBodyParameter)} must have a defaultContentType."); + parameter.CorrespondingMethodParams = correspondingMethodParams; return parameter; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEndpointParameterConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEndpointParameterConverter.cs index 7fdbf820a88..84cf579b721 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEndpointParameterConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEndpointParameterConverter.cs @@ -64,6 +64,7 @@ internal static InputEndpointParameter ReadInputEndpointParameter(ref Utf8JsonRe string? serverUrlTemplate = null; bool isEndpoint = false; IReadOnlyList? decorators = null; + IReadOnlyList? correspondingMethodParams = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -82,7 +83,8 @@ internal static InputEndpointParameter ReadInputEndpointParameter(ref Utf8JsonRe || reader.TryReadString("scope", ref scope) || reader.TryReadBoolean("skipUrlEncoding", ref skipUrlEncoding) || reader.TryReadBoolean("isEndpoint", ref isEndpoint) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("correspondingMethodParams", options, ref correspondingMethodParams); if (!isKnownProperty) { @@ -103,8 +105,9 @@ internal static InputEndpointParameter ReadInputEndpointParameter(ref Utf8JsonRe parameter.IsApiVersion = isApiVersion; parameter.DefaultValue = defaultValue; parameter.IsEndpoint = isEndpoint; - parameter.Scope = InputParameter.ParseScope(type, name, scope);; + parameter.Scope = InputParameter.ParseScope(type, name, scope); parameter.SkipUrlEncoding = skipUrlEncoding; + parameter.CorrespondingMethodParams = correspondingMethodParams; return parameter; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputHeaderParameterConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputHeaderParameterConverter.cs index cbd522550e8..e22c62f479c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputHeaderParameterConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputHeaderParameterConverter.cs @@ -64,6 +64,7 @@ internal static InputHeaderParameter ReadInputHeaderParameter(ref Utf8JsonReader string? access = null; string? collectionFormat = null; IReadOnlyList? decorators = null; + IReadOnlyList? correspondingMethodParams = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -82,7 +83,8 @@ internal static InputHeaderParameter ReadInputHeaderParameter(ref Utf8JsonReader || reader.TryReadString("scope", ref scope) || reader.TryReadString("arraySerializationDelimiter", ref arraySerializationDelimiter) || reader.TryReadBoolean("isContentType", ref isContentType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("correspondingMethodParams", options, ref correspondingMethodParams); if (!isKnownProperty) { @@ -102,9 +104,10 @@ internal static InputHeaderParameter ReadInputHeaderParameter(ref Utf8JsonReader parameter.SerializedName = serializedName ?? throw new JsonException($"{nameof(InputHeaderParameter)} must have a serializedName."); parameter.IsApiVersion = isApiVersion; parameter.DefaultValue = defaultValue; - parameter.Scope = InputParameter.ParseScope(type, name, scope);; + parameter.Scope = InputParameter.ParseScope(type, name, scope); parameter.ArraySerializationDelimiter = arraySerializationDelimiter; parameter.IsContentType = isContentType; + parameter.CorrespondingMethodParams = correspondingMethodParams; return parameter; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPathParameterConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPathParameterConverter.cs index 185466eaf56..12165ee282d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPathParameterConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPathParameterConverter.cs @@ -66,6 +66,7 @@ internal static InputPathParameter ReadInputPathParameter(ref Utf8JsonReader rea string? serverUrlTemplate = null; bool allowReserved = false; IReadOnlyList? decorators = null; + IReadOnlyList? correspondingMethodParams = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -85,7 +86,8 @@ internal static InputPathParameter ReadInputPathParameter(ref Utf8JsonReader rea || reader.TryReadString("scope", ref scope) || reader.TryReadBoolean("explode", ref explode) || reader.TryReadBoolean("skipUrlEncoding", ref skipUrlEncoding) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("correspondingMethodParams", options, ref correspondingMethodParams); if (!isKnownProperty) { @@ -106,9 +108,10 @@ internal static InputPathParameter ReadInputPathParameter(ref Utf8JsonReader rea parameter.SerializedName = serializedName ?? throw new JsonException($"{nameof(InputPathParameter)} must have a serializedName."); parameter.IsApiVersion = isApiVersion; parameter.DefaultValue = defaultValue; - parameter.Scope = InputParameter.ParseScope(type, name, scope);; + parameter.Scope = InputParameter.ParseScope(type, name, scope); parameter.Explode = explode; parameter.SkipUrlEncoding = skipUrlEncoding; + parameter.CorrespondingMethodParams = correspondingMethodParams; return parameter; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputQueryParameterConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputQueryParameterConverter.cs index 066e9469e6c..27f3de858c8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputQueryParameterConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputQueryParameterConverter.cs @@ -64,6 +64,7 @@ internal static InputQueryParameter ReadInputQueryParameter(ref Utf8JsonReader r string? collectionFormat = null; bool explode = false; IReadOnlyList? decorators = null; + IReadOnlyList? correspondingMethodParams = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -82,7 +83,8 @@ internal static InputQueryParameter ReadInputQueryParameter(ref Utf8JsonReader r || reader.TryReadString("scope", ref scope) || reader.TryReadString("arraySerializationDelimiter", ref arraySerializationDelimiter) || reader.TryReadBoolean("explode", ref explode) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("correspondingMethodParams", options, ref correspondingMethodParams); if (!isKnownProperty) { @@ -103,8 +105,9 @@ internal static InputQueryParameter ReadInputQueryParameter(ref Utf8JsonReader r parameter.SerializedName = serializedName ?? throw new JsonException($"{nameof(InputQueryParameter)} must have a serializedName."); parameter.IsApiVersion = isApiVersion; parameter.DefaultValue = defaultValue; - parameter.Scope = InputParameter.ParseScope(type, name, scope);; + parameter.Scope = InputParameter.ParseScope(type, name, scope); parameter.ArraySerializationDelimiter = arraySerializationDelimiter; + parameter.CorrespondingMethodParams = correspondingMethodParams; return parameter; }