@@ -56,7 +56,8 @@ public static (string ExtensionMethods, string TypeAliases) GenerateExtensionMet
5656 path . Key ,
5757 operation . Key ,
5858 operation . Value ,
59- basePath
59+ basePath ,
60+ document . Components ? . Schemas
6061 ) ;
6162 if ( ! string . IsNullOrEmpty ( publicMethod ) )
6263 {
@@ -155,6 +156,34 @@ private static async Task<string> DeserializeError(
155156 var content = await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
156157 return string.IsNullOrEmpty(content) ? "Unknown error" : content;
157158 }
159+
160+ private static string BuildQueryString(params (string Key, object? Value)[] parameters)
161+ {
162+ var parts = new List<string>();
163+ foreach (var (key, value) in parameters)
164+ {
165+ if (value == null)
166+ {
167+ continue;
168+ }
169+
170+ if (value is System.Collections.IEnumerable enumerable and not string)
171+ {
172+ foreach (var item in enumerable)
173+ {
174+ if (item != null)
175+ {
176+ parts.Add($"{key}={Uri.EscapeDataString(item.ToString() ?? string.Empty)}");
177+ }
178+ }
179+ }
180+ else
181+ {
182+ parts.Add($"{key}={Uri.EscapeDataString(value.ToString() ?? string.Empty)}");
183+ }
184+ }
185+ return parts.Count > 0 ? "?" + string.Join("&", parts) : string.Empty;
186+ }
158187 }
159188 """ ;
160189
@@ -208,11 +237,12 @@ private static (string PublicMethod, string PrivateDelegate) GenerateMethod(
208237 string path ,
209238 HttpMethod operationType ,
210239 OpenApiOperation operation ,
211- string basePath
240+ string basePath ,
241+ IDictionary < string , IOpenApiSchema > ? schemas = null
212242 )
213243 {
214244 var methodName = GetMethodName ( operation , operationType , path ) ;
215- var parameters = GetParameters ( operation ) ;
245+ var parameters = GetParameters ( operation , schemas ) ;
216246 var requestBodyType = GetRequestBodyType ( operation ) ;
217247 var responseType = GetResponseType ( operation ) ;
218248 var fullPath = $ "{ basePath } { path } ";
@@ -331,28 +361,20 @@ string summary
331361 var paramInvocation = isSingleParam ? nonPathParamsNames : $ "({ nonPathParamsNames } )";
332362 var deserializeMethod = isDelete ? "_deserializeUnit" : deserializer ;
333363
334- var queryString = hasQueryParams
364+ var queryStringExpression = hasQueryParams
335365 ? (
336366 isSingleParam && queryParams . Count == 1
337- ? "?"
338- + string . Join (
339- "&" ,
340- queryParams . Select ( q => $ "{ q . OriginalName } ={{param}}")
341- )
342- : "?"
343- + string . Join (
344- "&" ,
345- queryParams . Select ( q => $ "{ q . OriginalName } ={{param.{ q . Name } }}")
346- )
367+ ? $ "BuildQueryString((\" { queryParams [ 0 ] . OriginalName } \" , param))"
368+ : $ "BuildQueryString({ string . Join ( ", " , queryParams . Select ( q => $ "(\" { q . OriginalName } \" , param.{ q . Name } )") ) } )"
347369 )
348- : string . Empty ;
370+ : " string.Empty" ;
349371
350372 var headersExpression = hasHeaderParams
351373 ? BuildHeadersDictionaryExpression ( headerParams , "param" , isSingleParam )
352374 : "null" ;
353375
354376 var buildRequestBody =
355- $ "static param => new HttpRequestParts(new RelativeUrl($\" { path } { queryString } \" ), null, { headersExpression } )";
377+ $ "static param => new HttpRequestParts(new RelativeUrl($\" { path } {{{queryStringExpression}} }\" ), null, { headersExpression } )";
356378
357379 return BuildMethod (
358380 methodName ,
@@ -389,21 +411,13 @@ string summary
389411 var paramInvocation = isSingleParam ? allParamsNames : $ "({ allParamsNames } )";
390412 var deserializeMethod = isDelete ? "_deserializeUnit" : deserializer ;
391413
392- var queryString = hasQueryParams
414+ var queryStringExpression = hasQueryParams
393415 ? (
394416 isSingleParam && queryParams . Count == 1
395- ? "?"
396- + string . Join (
397- "&" ,
398- queryParams . Select ( q => $ "{ q . OriginalName } ={{param}}")
399- )
400- : "?"
401- + string . Join (
402- "&" ,
403- queryParams . Select ( q => $ "{ q . OriginalName } ={{param.{ q . Name } }}")
404- )
417+ ? $ "BuildQueryString((\" { queryParams [ 0 ] . OriginalName } \" , param))"
418+ : $ "BuildQueryString({ string . Join ( ", " , queryParams . Select ( q => $ "(\" { q . OriginalName } \" , param.{ q . Name } )") ) } )"
405419 )
406- : string . Empty ;
420+ : " string.Empty" ;
407421
408422 var headersExpression = hasHeaderParams
409423 ? BuildHeadersDictionaryExpression ( headerParams , "param" , isSingleParam )
@@ -423,7 +437,7 @@ string summary
423437 : sanitizedPath . Replace ( "{" , "{param." , StringComparison . Ordinal ) ;
424438
425439 var buildRequestBody =
426- $ "static param => new HttpRequestParts(new RelativeUrl($\" { pathWithParam } { queryString } \" ), null, { headersExpression } )";
440+ $ "static param => new HttpRequestParts(new RelativeUrl($\" { pathWithParam } {{{queryStringExpression}} }\" ), null, { headersExpression } )";
427441
428442 return BuildMethod (
429443 methodName ,
@@ -506,20 +520,16 @@ string summary
506520 : sanitizedPath . Replace ( "{" , "{param.Params." , StringComparison . Ordinal )
507521 ) ;
508522
509- var queryString = hasQueryParams
510- ? "?"
511- + string . Join (
512- "&" ,
513- queryParams . Select ( q => $ "{ q . OriginalName } ={{param.{ q . Name } }}")
514- )
515- : string . Empty ;
523+ var queryStringExpression = hasQueryParams
524+ ? $ "BuildQueryString({ string . Join ( ", " , queryParams . Select ( q => $ "(\" { q . OriginalName } \" , param.{ q . Name } )") ) } )"
525+ : "string.Empty" ;
516526
517527 var headersExpression = hasHeaderParams
518528 ? BuildHeadersDictionaryExpression ( headerParams , "param" , false )
519529 : "null" ;
520530
521531 var buildRequestBody =
522- $ "static param => new HttpRequestParts(new RelativeUrl($\" { pathWithParamInterpolation } { queryString } \" ), CreateJsonContent(param.Body), { headersExpression } )";
532+ $ "static param => new HttpRequestParts(new RelativeUrl($\" { pathWithParamInterpolation } {{{queryStringExpression}} }\" ), CreateJsonContent(param.Body), { headersExpression } )";
523533
524534 // Public methods ALWAYS have individual parameters, never tuples
525535 var publicMethodParams = hasNonPathNonBodyParams
@@ -577,7 +587,10 @@ string path
577587 return $ "{ methodName } { CodeGenerationHelpers . ToPascalCase ( pathPart ) } ";
578588 }
579589
580- private static List < ParameterInfo > GetParameters ( OpenApiOperation operation )
590+ private static List < ParameterInfo > GetParameters (
591+ OpenApiOperation operation ,
592+ IDictionary < string , IOpenApiSchema > ? schemas = null
593+ )
581594 {
582595 var parameters = new List < ParameterInfo > ( ) ;
583596
@@ -595,7 +608,7 @@ private static List<ParameterInfo> GetParameters(OpenApiOperation operation)
595608
596609 var isPath = param . In == ParameterLocation . Path ;
597610 var isHeader = param . In == ParameterLocation . Header ;
598- var type = ModelGenerator . MapOpenApiType ( param . Schema ) ;
611+ var type = ModelGenerator . MapOpenApiType ( param . Schema , schemas ) ;
599612 var sanitizedName = CodeGenerationHelpers . ToCamelCase ( param . Name ) ;
600613 parameters . Add ( new ParameterInfo ( sanitizedName , type , isPath , isHeader , param . Name ) ) ;
601614 }
0 commit comments