From e22c76777ec1801af207c24ce3098d62eee7c3c4 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 22 May 2025 16:31:05 +0800 Subject: [PATCH 1/8] Initial upload mustache templates for DWB --- .../generichost/ApiException.mustache | 14 + .../generichost/ApiResponse`1.mustache | 50 ++ .../generichost/HostConfiguration.mustache | 23 +- .../libraries/generichost/IApi.mustache | 37 ++ .../generichost/ModelSignature.mustache | 2 +- .../generichost/OperationSignature.mustache | 2 +- .../generichost/README.client.mustache | 4 +- .../csharp/libraries/generichost/api.mustache | 436 +++++------------- .../libraries/generichost/api_test.mustache | 29 +- .../libraries/generichost/model.mustache | 1 - .../generichost/modelGeneric.mustache | 56 +-- 11 files changed, 248 insertions(+), 406 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiException.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiException.mustache index c14c1010ffd7..dbb794c79b4a 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiException.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiException.mustache @@ -5,6 +5,7 @@ {{/nrt}} using System; +using System.Net.Http; namespace {{packageName}}.{{clientPackage}} { @@ -43,4 +44,17 @@ namespace {{packageName}}.{{clientPackage}} RawContent = rawContent; } } + + {{>visibility}} class HttpOperationException : Exception + { + {{>visibility}} HttpRequestMessage Request { get; } + {{>visibility}} HttpResponseMessage Response { get; } + + {{>visibility}} HttpOperationException(HttpRequestMessage request, HttpResponseMessage response, string message) + : base(message) + { + Request = request; + Response = response; + } + } } diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiResponse`1.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiResponse`1.mustache index 1b12e4173931..04e4ed2e6174 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiResponse`1.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiResponse`1.mustache @@ -9,6 +9,7 @@ using System; using System.Diagnostics.CodeAnalysis; {{/netStandard}} using System.Net; +using System.Net.Http; namespace {{packageName}}.{{clientPackage}} { @@ -167,4 +168,53 @@ namespace {{packageName}}.{{clientPackage}} bool Try{{.}}({{#net60OrLater}}[NotNullWhen(true)]{{/net60OrLater}}out TType{{nrt?}} result); } {{/x-http-statuses-with-return}} + + {{>visibility}} interface IHttpOperationResponse + { + HttpRequestMessage Request { get; set; } + + HttpResponseMessage Response { get; set; } + } + {{>visibility}} interface IHttpOperationResponse : IHttpOperationResponse + { + T Body { get; set; } + } + {{>visibility}} class HttpOperationResponse : IHttpOperationResponse, IDisposable + { + private bool _disposed; + + {{>visibility}} HttpRequestMessage Request { get; set; } + + {{>visibility}} HttpResponseMessage Response { get; set; } + + {{>visibility}} void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + _disposed = true; + if (Request != null) + { + Request.Dispose(); + } + + if (Response != null) + { + Response.Dispose(); + } + + Request = null; + Response = null; + } + } + } + {{>visibility}} class HttpOperationResponse : HttpOperationResponse, IHttpOperationResponse, IHttpOperationResponse + { + {{>visibility}} T Body { get; set; } + } } diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache index 1333f0e67ea2..13a784d4aef1 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache @@ -43,17 +43,7 @@ namespace {{packageName}}.{{clientPackage}} _jsonOptions.Converters.Add(new DateOnlyJsonConverter()); _jsonOptions.Converters.Add(new DateOnlyNullableJsonConverter()); {{/supportsDateOnly}} - {{#models}} - {{#model}} - {{#isEnum}} - _jsonOptions.Converters.Add(new {{datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}JsonConverter()); - _jsonOptions.Converters.Add(new {{datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}NullableJsonConverter()); - {{/isEnum}} - {{^isEnum}} - _jsonOptions.Converters.Add(new {{classname}}JsonConverter()); - {{/isEnum}} - {{/model}} - {{/models}} + JsonSerializerOptionsProvider jsonSerializerOptionsProvider = new{{^net60OrLater}} JsonSerializerOptionsProvider{{/net60OrLater}}(_jsonOptions); _services.AddSingleton(jsonSerializerOptionsProvider); {{#useSourceGeneration}} @@ -66,7 +56,7 @@ namespace {{packageName}}.{{clientPackage}} {{#lambda.joinLinesWithComma}} {{#models}} {{#model}} - new {{datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}SerializationContext(){{#-last}},{{/-last}} + new {{datatypeWithEnum}}{{^datatypeWithEnum}}{{baseName}}{{/datatypeWithEnum}}SerializationContext(){{#-last}},{{/-last}} {{/model}} {{/models}} {{/lambda.joinLinesWithComma}} @@ -79,9 +69,8 @@ namespace {{packageName}}.{{clientPackage}} {{/models}} {{/useSourceGeneration}} - _services.AddSingleton();{{#apiInfo}}{{#apis}} - _services.AddSingleton<{{classname}}Events>(); - _services.AddTransient<{{interfacePrefix}}{{classname}}, {{classname}}>();{{/apis}}{{/apiInfo}} + _services.AddSingleton(); + _services.AddTransient<{{interfacePrefix}}{{clientName}}, {{clientName}}>(); } /// @@ -99,8 +88,8 @@ namespace {{packageName}}.{{clientPackage}} List builders = new List(); - {{#apiInfo}}{{#apis}}builders.Add(_services.AddHttpClient<{{interfacePrefix}}{{classname}}, {{classname}}>(client)); - {{/apis}}{{/apiInfo}} + builders.Add(_services.AddHttpClient<{{interfacePrefix}}{{clientName}}, {{clientName}}>(client)); + if (builder != null) foreach (IHttpClientBuilder instance in builders) builder(instance); diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache index af31cffe9293..cc978d7b1de2 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache @@ -1,4 +1,6 @@ using System.Net.Http; +using {{packageName}}.{{clientPackage}}; +using {{packageName}}.{{apiPackage}}; namespace {{packageName}}.{{apiPackage}} { @@ -12,4 +14,39 @@ namespace {{packageName}}.{{apiPackage}} /// HttpClient HttpClient { get; } } + + /// + /// + public partial interface {{interfacePrefix}}{{clientName}} + { + JsonSerializerOptionsProvider JsonSerializerOptionsProvider { get; } + +{{#apiInfo.apis}} + {{interfacePrefix}}{{baseName}} {{baseName}} { get; } +{{/apiInfo.apis}} + + } +} + +namespace {{packageName}} +{ + public class {{clientName}} : {{interfacePrefix}}{{clientName}} + { + public HttpClient HttpClient { get; } + public JsonSerializerOptionsProvider JsonSerializerOptionsProvider { get; private set; } +{{#apiInfo.apis}} + {{>visibility}} virtual {{interfacePrefix}}{{baseName}} {{baseName}} { get; private set; } +{{/apiInfo.apis}} + + public {{clientName}}( + HttpClient httpClient, JsonSerializerOptionsProvider jsonSerializerOptionsProvider) + { + HttpClient = httpClient; + JsonSerializerOptionsProvider = jsonSerializerOptionsProvider; +{{#apiInfo.apis}} + {{baseName}} = new {{baseName}}(httpClient, jsonSerializerOptionsProvider); +{{/apiInfo.apis}} + } + + } } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache index 39aa11f82abe..d5cf70bd67fa 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache @@ -1 +1 @@ -{{#model.allVars}}{{^isDiscriminator}}{{^required}}Option<{{/required}}{{{datatypeWithEnum}}}{{>NullConditionalProperty}}{{^required}}>{{/required}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}{{#defaultValue}} = {{^required}}default{{/required}}{{#required}}{{^isDateTime}}{{#isString}}{{^isEnum}}@{{/isEnum}}{{/isString}}{{{.}}}{{/isDateTime}}{{#isDateTime}}default{{/isDateTime}}{{/required}}{{/defaultValue}}{{^defaultValue}}{{#lambda.first}}{{#isNullable}} = default {{/isNullable}}{{^required}} = default {{/required}}{{/lambda.first}}{{/defaultValue}} {{/isDiscriminator}}{{/model.allVars}} +{{#model.allVars}}{{^isDiscriminator}}{{{datatypeWithEnum}}}{{#isNullable}}{{>NullConditionalProperty}}{{/isNullable}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}{{#defaultValue}} = {{^required}}default{{/required}}{{#required}}{{^isDateTime}}{{#isString}}{{^isEnum}}@{{/isEnum}}{{/isString}}{{{.}}}{{/isDateTime}}{{#isDateTime}}default{{/isDateTime}}{{/required}}{{/defaultValue}}{{^defaultValue}}{{#lambda.first}}{{#isNullable}} = default {{/isNullable}}{{^required}} = default {{/required}}{{/lambda.first}}{{/defaultValue}} {{/isDiscriminator}}{{/model.allVars}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/OperationSignature.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/OperationSignature.mustache index caa9d144c52d..4f3f673b9469 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/OperationSignature.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/OperationSignature.mustache @@ -1 +1 @@ -{{#lambda.joinWithComma}}{{#allParams}}{{#required}}{{{dataType}}}{{>NullConditionalParameter}}{{/required}}{{^required}}Option<{{{dataType}}}{{>NullConditionalParameter}}>{{/required}} {{paramName}}{{#notRequiredOrIsNullable}} = default{{/notRequiredOrIsNullable}} {{/allParams}}System.Threading.CancellationToken cancellationToken = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}}{{/lambda.joinWithComma}} \ No newline at end of file +{{#lambda.joinWithComma}}{{#allParams}}{{{dataType}}}{{>NullConditionalParameter}} {{paramName}}{{#notRequiredOrIsNullable}} = default{{/notRequiredOrIsNullable}} {{/allParams}}System.Threading.CancellationToken cancellationToken = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}}{{/lambda.joinWithComma}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache index 371b9daa9211..7f864db5fd92 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache @@ -66,7 +66,7 @@ namespace YourProject {{#-first}} {{#operation}} {{#-first}} - {{operationId}}ApiResponse apiResponse = await api.{{operationId}}Async("todo"); + {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}ApiResponse apiResponse = await api.{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async("todo"); {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}object{{/returnType}} model = apiResponse.Ok(); {{/-first}} {{/operation}} @@ -138,7 +138,7 @@ All URIs are relative to *{{{basePath}}}* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | -------------{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} -*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}{{/apiDocs}}{{#modelDocs}} +*{{classname}}* | [**{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}{{/apiDocs}}{{#modelDocs}} ## Documentation for Models diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache index 1c872fd8afb7..0191b0df2228 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache @@ -24,6 +24,8 @@ using Microsoft.Extensions.Logging; using System.Net.Http; using System.Net.Http.Headers; using System.Text.Json; +using System.Text.Json.Serialization; +using System.Xml; using {{packageName}}.{{clientPackage}}; {{#hasImport}} using {{packageName}}.{{modelPackage}}; @@ -31,21 +33,17 @@ using {{packageName}}.{{modelPackage}}; {{^netStandard}} using System.Diagnostics.CodeAnalysis; {{/netStandard}} +using {{packageName}}.{{package}}; -namespace {{packageName}}.{{apiPackage}} +namespace {{packageName}}.{{package}} { {{#operations}} /// /// Represents a collection of functions to interact with the API endpoints /// This class is registered as transient. /// - {{>visibility}} interface {{interfacePrefix}}{{classname}} : IApi + {{>visibility}} interface {{interfacePrefix}}{{baseName}} : IApi { - /// - /// The class containing the events - /// - {{classname}}Events Events { get; } - {{#operation}} /// /// {{summary}} @@ -55,14 +53,17 @@ namespace {{packageName}}.{{apiPackage}} /// /// Thrown when fails to make API call {{#allParams}} - /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}} + /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} {{/allParams}} + /// The headers that will be added to request. /// Cancellation Token to cancel the request. - /// <> - {{#isDeprecated}} - [Obsolete] - {{/isDeprecated}} - Task<{{interfacePrefix}}{{operationId}}ApiResponse> {{operationId}}Async({{>OperationSignature}}); + /// <> + Task{{/returnType}}> {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}WithHttpMessagesAsync( + {{#allParams}} + {{{dataType}}} {{paramName}}{{^required}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}} = default{{/isNullable}}{{/required}}, + {{/allParams}} + Dictionary> customHeaders = null, + System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// /// {{summary}} @@ -70,113 +71,44 @@ namespace {{packageName}}.{{apiPackage}} /// /// {{notes}} /// + /// Thrown when fails to make API call {{#allParams}} - /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}} + /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} {{/allParams}} /// Cancellation Token to cancel the request. - /// <{{nrt?}}> - {{#isDeprecated}} - [Obsolete] - {{/isDeprecated}} - Task<{{interfacePrefix}}{{operationId}}ApiResponse{{nrt?}}> {{operationId}}OrDefaultAsync({{>OperationSignature}}); - {{^-last}} - - {{/-last}} - {{/operation}} - } - {{#operation}} - {{^vendorExtensions.x-duplicates}} - {{#responses}} - {{#-first}} + /// {{#returnType}}<>{{/returnType}} + Task{{#returnType}}<{{{returnType}}}>{{/returnType}} {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async( + {{#allParams}} + {{{dataType}}} {{paramName}}{{^required}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}} = default{{/isNullable}}{{/required}}, + {{/allParams}} + System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - /// - /// The - /// - {{>visibility}} interface {{interfacePrefix}}{{operationId}}ApiResponse : {{#lambda.joinWithComma}}{{packageName}}.{{clientPackage}}.{{interfacePrefix}}ApiResponse {{#responses}}{{#dataType}}{{interfacePrefix}}{{vendorExtensions.x-http-status}}<{{#isModel}}{{^containerType}}{{packageName}}.{{modelPackage}}.{{/containerType}}{{/isModel}}{{{dataType}}}{{#nrt}}?{{/nrt}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}}> {{/dataType}}{{/responses}}{{/lambda.joinWithComma}} - { - {{#responses}} - {{#vendorExtensions.x-http-status-is-default}} - /// - /// Returns true if the response is the default response type - /// - /// - bool Is{{vendorExtensions.x-http-status}} { get; } - {{/vendorExtensions.x-http-status-is-default}} - {{^vendorExtensions.x-http-status-is-default}} - /// - /// Returns true if the response is {{code}} {{vendorExtensions.x-http-status}} - /// - /// - bool Is{{vendorExtensions.x-http-status}} { get; } - {{/vendorExtensions.x-http-status-is-default}} {{^-last}} {{/-last}} - {{/responses}} + {{/operation}} } - {{/-first}} - {{/responses}} - {{/vendorExtensions.x-duplicates}} - {{/operation}} - - /// - /// Represents a collection of functions to interact with the API endpoints - /// - {{>visibility}} class {{classname}}Events - { - {{#lambda.trimTrailingWithNewLine}} - {{#operation}} - /// - /// The event raised after the server response - /// - public event EventHandler{{nrt?}} On{{operationId}}; - /// - /// The event raised after an error querying the server - /// - public event EventHandler{{nrt?}} OnError{{operationId}}; - - internal void ExecuteOn{{operationId}}({{#vendorExtensions.x-duplicates}}{{.}}{{/vendorExtensions.x-duplicates}}{{^vendorExtensions.x-duplicates}}{{classname}}{{/vendorExtensions.x-duplicates}}.{{operationId}}ApiResponse apiResponse) - { - On{{operationId}}?.Invoke(this, new ApiResponseEventArgs(apiResponse)); - } - - internal void ExecuteOnError{{operationId}}(Exception exception) - { - OnError{{operationId}}?.Invoke(this, new ExceptionEventArgs(exception)); - } + {{/operations}} +} - {{/operation}} - {{/lambda.trimTrailingWithNewLine}} - } +namespace {{packageName}} +{ + {{#operations}} /// /// Represents a collection of functions to interact with the API endpoints /// - {{>visibility}} sealed partial class {{classname}} : {{interfacePrefix}}{{classname}} + {{>visibility}} sealed partial class {{baseName}} : {{interfacePrefix}}{{baseName}} { private JsonSerializerOptions _jsonSerializerOptions; - /// - /// The logger factory - /// - public ILoggerFactory LoggerFactory { get; } - - /// - /// The logger - /// - public ILogger<{{classname}}> Logger { get; } - /// /// The HttpClient /// public HttpClient HttpClient { get; } - /// - /// The class containing the events - /// - public {{classname}}Events Events { get; }{{#hasApiKeyMethods}} - + {{#hasApiKeyMethods}} /// /// A token provider of type /// @@ -216,10 +148,10 @@ namespace {{packageName}}.{{apiPackage}} {{/lambda.unique}} {{/net80OrLater}} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - public {{classname}}(ILogger<{{classname}}> logger, ILoggerFactory loggerFactory, HttpClient httpClient, JsonSerializerOptionsProvider jsonSerializerOptionsProvider, {{classname}}Events {{#lambda.camelcase_sanitize_param}}{{classname}}Events{{/lambda.camelcase_sanitize_param}}{{#hasApiKeyMethods}}, + public {{baseName}}(HttpClient httpClient, JsonSerializerOptionsProvider jsonSerializerOptionsProvider {{#hasApiKeyMethods}}, TokenProvider apiKeyProvider{{/hasApiKeyMethods}}{{#hasHttpBearerMethods}}, TokenProvider bearerTokenProvider{{/hasHttpBearerMethods}}{{#hasHttpBasicMethods}}, TokenProvider basicTokenProvider{{/hasHttpBasicMethods}}{{#hasHttpSignatureMethods}}, @@ -228,10 +160,7 @@ namespace {{packageName}}.{{apiPackage}} {{packageName}}.{{clientPackage}}.CookieContainer cookieContainer{{/vendorExtensions.x-set-cookie}}{{/lambda.uniqueLines}}{{/operation}}{{/net80OrLater}}) { _jsonSerializerOptions = jsonSerializerOptionsProvider.Options; - LoggerFactory = loggerFactory; - Logger = LoggerFactory.CreateLogger<{{classname}}>(); - HttpClient = httpClient; - Events = {{#lambda.camelcase_sanitize_param}}{{classname}}Events{{/lambda.camelcase_sanitize_param}};{{#hasApiKeyMethods}} + HttpClient = httpClient;{{#hasApiKeyMethods}} ApiKeyProvider = apiKeyProvider;{{/hasApiKeyMethods}}{{#hasHttpBearerMethods}} BearerTokenProvider = bearerTokenProvider;{{/hasHttpBearerMethods}}{{#hasHttpBasicMethods}} BasicTokenProvider = basicTokenProvider;{{/hasHttpBasicMethods}}{{#hasHttpSignatureMethods}} @@ -243,7 +172,7 @@ namespace {{packageName}}.{{apiPackage}} {{#allParams}} {{#-first}} - partial void Format{{operationId}}({{#allParams}}{{#isPrimitiveType}}ref {{/isPrimitiveType}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); + partial void Format{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#allParams}}{{#isPrimitiveType}}ref {{/isPrimitiveType}}{{{dataType}}}{{>NullConditionalParameter}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); {{/-first}} {{/allParams}} @@ -255,52 +184,20 @@ namespace {{packageName}}.{{apiPackage}} /// {{/vendorExtensions.x-not-nullable-reference-types}} /// - private void Validate{{operationId}}({{#vendorExtensions.x-not-nullable-reference-types}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-not-nullable-reference-types}}) + private void Validate{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#vendorExtensions.x-not-nullable-reference-types}}{{{dataType}}}{{>NullConditionalParameter}} {{paramName}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-not-nullable-reference-types}}) { {{#lambda.trimTrailingWithNewLine}} {{#vendorExtensions.x-not-nullable-reference-types}} - {{#required}} {{^vendorExtensions.x-is-value-type}} if ({{paramName}} == null) throw new ArgumentNullException(nameof({{paramName}})); {{/vendorExtensions.x-is-value-type}} - {{/required}} - {{^required}} - {{^vendorExtensions.x-is-value-type}} - if ({{paramName}}.IsSet && {{paramName}}.Value == null) - throw new ArgumentNullException(nameof({{paramName}})); - - {{/vendorExtensions.x-is-value-type}} - {{/required}} {{/vendorExtensions.x-not-nullable-reference-types}} {{/lambda.trimTrailingWithNewLine}} } {{/vendorExtensions.x-has-not-nullable-reference-types}} - /// - /// Processes the server response - /// - /// - {{#allParams}} - /// - {{/allParams}} - private void After{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}{{interfacePrefix}}{{operationId}}ApiResponse apiResponseLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}) - { - bool suppressDefaultLog = false; - After{{operationId}}({{#lambda.joinWithComma}}ref suppressDefaultLog apiResponseLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); -{{>AfterOperationDefaultImplementation}} - } - - /// - /// Processes the server response - /// - /// - /// - {{#allParams}} - /// - {{/allParams}} - partial void After{{operationId}}({{#lambda.joinWithComma}}ref bool suppressDefaultLog {{interfacePrefix}}{{operationId}}ApiResponse apiResponseLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); /// /// Logs exceptions that occur while retrieving the server response @@ -311,11 +208,10 @@ namespace {{packageName}}.{{apiPackage}} {{#allParams}} /// {{/allParams}} - private void OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}) + private void OnError{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}DefaultImplementation({{#lambda.joinWithComma}}Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{{dataType}}}{{>NullConditionalParameter}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}) { bool suppressDefaultLogLocalVar = false; - OnError{{operationId}}({{#lambda.joinWithComma}}ref suppressDefaultLogLocalVar exceptionLocalVar pathFormatLocalVar pathLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); -{{>OnErrorDefaultImplementation}} + OnError{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#lambda.joinWithComma}}ref suppressDefaultLogLocalVar exceptionLocalVar pathFormatLocalVar pathLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); } /// @@ -328,38 +224,27 @@ namespace {{packageName}}.{{apiPackage}} {{#allParams}} /// {{/allParams}} - partial void OnError{{operationId}}({{#lambda.joinWithComma}}ref bool suppressDefaultLogLocalVar Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); + partial void OnError{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#lambda.joinWithComma}}ref bool suppressDefaultLogLocalVar Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{{dataType}}}{{>NullConditionalParameter}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); /// - /// {{summary}} {{notes}} - /// - {{#allParams}} - /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} - {{/allParams}} - /// Cancellation Token to cancel the request. - /// <> - public async Task<{{interfacePrefix}}{{operationId}}ApiResponse{{nrt?}}> {{operationId}}OrDefaultAsync({{>OperationSignature}}) - { - try - { - return await {{operationId}}Async({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#allParams.0}}, {{/allParams.0}}cancellationToken).ConfigureAwait(false); - } - catch (Exception) - { - return null; - } - } - - /// - /// {{summary}} {{notes}} + /// {{summary}} /// + /// + /// {{notes}} + /// /// Thrown when fails to make API call {{#allParams}} /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} {{/allParams}} + /// The headers that will be added to request. /// Cancellation Token to cancel the request. - /// <> - public async Task<{{interfacePrefix}}{{operationId}}ApiResponse> {{operationId}}Async({{>OperationSignature}}) + /// <> + public async Task{{/returnType}}> {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}WithHttpMessagesAsync( + {{#allParams}} + {{{dataType}}} {{paramName}}{{^required}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}} = default{{/isNullable}}{{/required}}, + {{/allParams}} + Dictionary> customHeaders = null, + System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { {{#lambda.trimLineBreaks}} UriBuilder uriBuilderLocalVar = new UriBuilder(); @@ -367,12 +252,12 @@ namespace {{packageName}}.{{apiPackage}} try { {{#vendorExtensions.x-has-not-nullable-reference-types}} - Validate{{operationId}}({{#vendorExtensions.x-not-nullable-reference-types}}{{paramName}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-not-nullable-reference-types}}); + //Validate{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#vendorExtensions.x-not-nullable-reference-types}}{{paramName}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-not-nullable-reference-types}}); {{/vendorExtensions.x-has-not-nullable-reference-types}} {{#allParams}} {{#-first}} - Format{{operationId}}({{#allParams}}{{#isPrimitiveType}}ref {{/isPrimitiveType}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); + Format{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}({{#allParams}}{{#isPrimitiveType}}ref {{/isPrimitiveType}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); {{/-first}} {{/allParams}} @@ -427,8 +312,8 @@ namespace {{packageName}}.{{apiPackage}} {{#-first}} {{/-first}} - parseQueryStringLocalVar["{{baseName}}"] = ClientUtils.ParameterToString({{paramName}}); {{/required}} + parseQueryStringLocalVar["{{baseName}}"] = ClientUtils.ParameterToString({{paramName}}); {{/queryParams}} {{#constantParams}} @@ -438,11 +323,7 @@ namespace {{packageName}}.{{apiPackage}} {{/isQueryParam}} {{/constantParams}} {{#queryParams}} - {{^required}} - if ({{paramName}}.IsSet) - parseQueryStringLocalVar["{{baseName}}"] = ClientUtils.ParameterToString({{paramName}}.Value); - {{/required}} {{#-last}} uriBuilderLocalVar.Query = parseQueryStringLocalVar.ToString(); @@ -455,16 +336,20 @@ namespace {{packageName}}.{{apiPackage}} {{/isHeaderParam}} {{/constantParams}} {{#headerParams}} - {{#required}} - httpRequestMessageLocalVar.Headers.Add("{{baseName}}", ClientUtils.ParameterToString({{paramName}})); + if ({{paramName}} != null) + httpRequestMessageLocalVar.Headers.Add("{{baseName}}", ClientUtils.ParameterToString({{paramName}})); - {{/required}} - {{^required}} - if ({{paramName}}.IsSet) - httpRequestMessageLocalVar.Headers.Add("{{baseName}}", ClientUtils.ParameterToString({{paramName}}.Value)); - - {{/required}} {{/headerParams}} + + // Add custom headers + if (customHeaders != null) + { + foreach (var header in customHeaders) + { + httpRequestMessageLocalVar.Headers.Add(header.Key, header.Value); + } + } + {{#formParams}} {{#-first}} MultipartContent multipartContentLocalVar = new MultipartContent(); @@ -473,41 +358,20 @@ namespace {{packageName}}.{{apiPackage}} List> formParameterLocalVars = new List>(); - multipartContentLocalVar.Add(new FormUrlEncodedContent(formParameterLocalVars));{{/-first}}{{^isFile}}{{#required}} + multipartContentLocalVar.Add(new FormUrlEncodedContent(formParameterLocalVars));{{/-first}}{{^isFile}} formParameterLocalVars.Add(new KeyValuePair("{{baseName}}", ClientUtils.ParameterToString({{paramName}}))); - {{/required}} - {{^required}} - if ({{paramName}}.IsSet) - formParameterLocalVars.Add(new KeyValuePair("{{baseName}}", ClientUtils.ParameterToString({{paramName}}.Value))); - - {{/required}} {{/isFile}} {{#isFile}} - {{#required}} multipartContentLocalVar.Add(new StreamContent({{paramName}})); - {{/required}} - {{^required}} - if ({{paramName}}.IsSet) - multipartContentLocalVar.Add(new StreamContent({{paramName}}.Value)); - - {{/required}} {{/isFile}} {{/formParams}} {{#bodyParam}} - {{#required}} - httpRequestMessageLocalVar.Content = ({{paramName}}{{^required}}.Value{{/required}} as object) is System.IO.Stream stream + httpRequestMessageLocalVar.Content = ({{paramName}} as object) is System.IO.Stream stream ? httpRequestMessageLocalVar.Content = new StreamContent(stream) - : httpRequestMessageLocalVar.Content = new StringContent(JsonSerializer.Serialize({{paramName}}{{^required}}.Value{{/required}}, _jsonSerializerOptions)); - {{/required}} - {{^required}} - if ({{paramName}}.IsSet) - httpRequestMessageLocalVar.Content = ({{paramName}}{{^required}}.Value{{/required}} as object) is System.IO.Stream stream - ? httpRequestMessageLocalVar.Content = new StreamContent(stream) - : httpRequestMessageLocalVar.Content = new StringContent(JsonSerializer.Serialize({{paramName}}{{^required}}.Value{{/required}}, _jsonSerializerOptions)); - {{/required}} + : httpRequestMessageLocalVar.Content = new StringContent(JsonSerializer.Serialize({{paramName}}, _jsonSerializerOptions)); {{/bodyParam}} {{#authMethods}} @@ -621,15 +485,14 @@ namespace {{packageName}}.{{apiPackage}} using (HttpResponseMessage httpResponseMessageLocalVar = await HttpClient.SendAsync(httpRequestMessageLocalVar, cancellationToken).ConfigureAwait(false)) { - string responseContentLocalVar = await httpResponseMessageLocalVar.Content.ReadAsStringAsync({{#net60OrLater}}cancellationToken{{/net60OrLater}}).ConfigureAwait(false); - - ILogger<{{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse> apiResponseLoggerLocalVar = LoggerFactory.CreateLogger<{{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse>(); - - {{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse apiResponseLocalVar = new{{^net60OrLater}} {{operationId}}ApiResponse{{/net60OrLater}}(apiResponseLoggerLocalVar, httpRequestMessageLocalVar, httpResponseMessageLocalVar, responseContentLocalVar, "{{{path}}}", requestedAtLocalVar, _jsonSerializerOptions); - - After{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}apiResponseLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); - - Events.ExecuteOn{{operationId}}(apiResponseLocalVar); + string responseContentLocalVar = string.Empty; + if (httpResponseMessageLocalVar.Content != null) { + responseContentLocalVar = await httpResponseMessageLocalVar.Content.ReadAsStringAsync({{#net60OrLater}}cancellationToken{{/net60OrLater}}).ConfigureAwait(false); + } + if (!httpResponseMessageLocalVar.IsSuccessStatusCode) + { + throw new HttpOperationException(httpRequestMessageLocalVar, httpResponseMessageLocalVar, string.Format("Operation returned an invalid status code '{0}'", httpResponseMessageLocalVar.StatusCode)); + } {{#authMethods}} {{#-first}} @@ -672,132 +535,55 @@ namespace {{packageName}}.{{apiPackage}} {{/vendorExtensions.x-set-cookie}} {{/responses}} {{/net80OrLater}} - return apiResponseLocalVar; + return new HttpOperationResponse{{#returnType}}<{{{returnType}}}>{{/returnType}} + { + {{#returnType}}Body = JsonSerializer.Deserialize<{{{returnType}}}>(responseContentLocalVar, _jsonSerializerOptions),{{/returnType}} + Request = httpRequestMessageLocalVar, + Response = httpResponseMessageLocalVar + }; } } } catch(Exception e) { - OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}e "{{{path}}}" uriBuilderLocalVar.Path {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); - Events.ExecuteOnError{{operationId}}(e); + OnError{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}DefaultImplementation({{#lambda.joinWithComma}}e "{{{path}}}" uriBuilderLocalVar.Path {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}}); throw; } {{/lambda.trimLineBreaks}} } - {{^vendorExtensions.x-duplicates}} - {{#responses}} - {{#-first}} - + /// - /// The + /// {{summary}} /// - {{>visibility}} partial class {{operationId}}ApiResponse : {{packageName}}.{{clientPackage}}.ApiResponse, {{interfacePrefix}}{{operationId}}ApiResponse + /// + /// {{notes}} + /// + /// Thrown when fails to make API call + {{#allParams}} + /// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} + {{/allParams}} + /// Cancellation Token to cancel the request. + /// {{#returnType}}<>{{/returnType}} + public async Task{{#returnType}}<{{{returnType}}}>{{/returnType}} {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async( + {{#allParams}} + {{{dataType}}} {{paramName}}{{^required}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}} = default{{/isNullable}}{{/required}}, + {{/allParams}} + System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { - /// - /// The logger - /// - public ILogger<{{operationId}}ApiResponse> Logger { get; } - - /// - /// The - /// - /// - /// - /// - /// - /// - /// - /// - public {{operationId}}ApiResponse(ILogger<{{operationId}}ApiResponse> logger, System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage, string rawContent, string path, DateTime requestedAt, System.Text.Json.JsonSerializerOptions jsonSerializerOptions) : base(httpRequestMessage, httpResponseMessage, rawContent, path, requestedAt, jsonSerializerOptions) - { - Logger = logger; - OnCreated(httpRequestMessage, httpResponseMessage); - } - - partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage); - {{#responses}} - - {{#vendorExtensions.x-http-status-is-default}} - /// - /// Returns true if the response is the default response type - /// - /// - public bool Is{{vendorExtensions.x-http-status}} => {{#vendorExtensions.x-only-default}}true{{/vendorExtensions.x-only-default}}{{^vendorExtensions.x-only-default}}{{#lambda.joinConditions}}{{#responses}}{{^vendorExtensions.x-http-status-is-default}}!Is{{vendorExtensions.x-http-status}} {{/vendorExtensions.x-http-status-is-default}}{{/responses}}{{/lambda.joinConditions}}{{/vendorExtensions.x-only-default}}; - {{/vendorExtensions.x-http-status-is-default}} - {{^vendorExtensions.x-http-status-is-default}} - /// - /// Returns true if the response is {{code}} {{vendorExtensions.x-http-status}} - /// - /// - {{#vendorExtensions.x-http-status-range}} - public bool Is{{vendorExtensions.x-http-status}} - { - get - { - int statusCode = (int)StatusCode; - return {{vendorExtensions.x-http-status-range}}00 >= statusCode && {{vendorExtensions.x-http-status-range}}99 <= statusCode; - } - } - {{/vendorExtensions.x-http-status-range}} - {{^vendorExtensions.x-http-status-range}} - public bool Is{{vendorExtensions.x-http-status}} => {{code}} == (int)StatusCode; - {{/vendorExtensions.x-http-status-range}} - {{/vendorExtensions.x-http-status-is-default}} - {{#dataType}} - - /// - /// Deserializes the response if the response is {{code}} {{vendorExtensions.x-http-status}} - /// - /// - public {{#isModel}}{{^containerType}}{{packageName}}.{{modelPackage}}.{{/containerType}}{{/isModel}}{{{dataType}}}{{#nrt}}?{{/nrt}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{vendorExtensions.x-http-status}}() - { - {{#lambda.trimTrailingWithNewLine}} - {{#lambda.indent4}} - {{>AsModel}} - {{/lambda.indent4}} - {{/lambda.trimTrailingWithNewLine}} - } - - /// - /// Returns true if the response is {{code}} {{vendorExtensions.x-http-status}} and the deserialized response is not null - /// - /// - /// - public bool Try{{vendorExtensions.x-http-status}}({{#net60OrLater}}[NotNullWhen(true)]{{/net60OrLater}}out {{#isModel}}{{^containerType}}{{packageName}}.{{modelPackage}}.{{/containerType}}{{/isModel}}{{{dataType}}}{{#nrt}}?{{/nrt}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} result) - { - result = null; - - try - { - result = {{vendorExtensions.x-http-status}}(); - } catch (Exception e) - { - OnDeserializationErrorDefaultImplementation(e, (HttpStatusCode){{#vendorExtensions.x-http-status-range}}{{.}}{{/vendorExtensions.x-http-status-range}}{{^vendorExtensions.x-http-status-range}}{{code}}{{/vendorExtensions.x-http-status-range}}); - } - - return result != null; - } - {{/dataType}} - {{#-last}} - - private void OnDeserializationErrorDefaultImplementation(Exception exception, HttpStatusCode httpStatusCode) - { - bool suppressDefaultLog = false; - OnDeserializationError(ref suppressDefaultLog, exception, httpStatusCode); - {{#lambda.trimTrailingWithNewLine}} - {{#lambda.indent4}} - {{>OnDeserializationError}} - {{/lambda.indent4}} - {{/lambda.trimTrailingWithNewLine}} - } + // Call the WithHttpMessagesAsync method + {{#returnType}}var httpOperationResponse = {{/returnType}}await {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}WithHttpMessagesAsync( + {{#allParams}} + {{paramName}}, + {{/allParams}} + null, // customHeaders + cancellationToken).ConfigureAwait(false); - partial void OnDeserializationError(ref bool suppressDefaultLog, Exception exception, HttpStatusCode httpStatusCode); - {{/-last}} - {{/responses}} + {{#returnType}} + // Return the deserialized body + return httpOperationResponse.Body; + {{/returnType}} } - {{/-first}} - {{/responses}} - {{/vendorExtensions.x-duplicates}} + {{/operation}} } {{/operations}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api_test.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api_test.mustache index 02ce2216830c..3d05a9641b77 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api_test.mustache @@ -4,45 +4,44 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; using Microsoft.Extensions.DependencyInjection; -using {{packageName}}.{{apiPackage}};{{#hasImport}} +{{#hasImport}} using {{packageName}}.{{modelPackage}};{{/hasImport}} - +using {{packageName}}.Interfaces; {{>testInstructions}} -namespace {{packageName}}.Test.{{apiPackage}} +namespace {{packageName}}.Test.Interfaces { /// - /// Class for testing {{classname}} + /// Class for testing {{baseName}} /// - public sealed class {{classname}}Tests : ApiTestsBase + public sealed class {{baseName}}Tests : ApiTestsBase { - private readonly {{interfacePrefix}}{{classname}} _instance; + private readonly {{interfacePrefix}}{{baseName}} _instance; - public {{classname}}Tests(): base(Array.Empty()) + public {{baseName}}Tests(): base(Array.Empty()) { - _instance = _host.Services.GetRequiredService<{{interfacePrefix}}{{classname}}>(); + _instance = _host.Services.GetRequiredService<{{interfacePrefix}}{{baseName}}>(); } {{#operations}} {{#operation}} /// - /// Test {{operationId}} + /// Test {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}} /// [Fact (Skip = "not implemented")] - public async Task {{operationId}}AsyncTest() + public async Task {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}AsyncTest() { {{#allParams}} - {{^required}}Client.Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} = default{{nrt!}}; + {{{dataType}}}{{>NullConditionalParameter}} {{paramName}} = default{{nrt!}}; {{/allParams}} {{#returnType}} - var response = await _instance.{{operationId}}Async({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); - var model = response.{{#lambda.first}}{{#responses}}{{vendorExtensions.x-http-status}} {{/responses}}{{/lambda.first}}(); - Assert.IsType<{{{.}}}>(model); + var response = await _instance.{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); + Assert.IsType<{{{.}}}>(response); {{/returnType}} {{^returnType}} - await _instance.{{operationId}}Async({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); + await _instance.{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); {{/returnType}} } {{/operation}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/model.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/model.mustache index f9931574dcf5..0b062a5fe296 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/model.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/model.mustache @@ -41,7 +41,6 @@ namespace {{packageName}}.{{modelPackage}} {{^isEnum}} {{>modelGeneric}} -{{>JsonConverter}} {{/isEnum}} {{>SourceGenerationContext}} {{/model}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache index 04fb37138629..1e12f610cfc0 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache @@ -17,20 +17,20 @@ /// {{description}}{{^description}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/description}}{{#defaultValue}} (default to {{.}}){{/defaultValue}} {{/isDiscriminator}} {{/allVars}} - {{#model.vendorExtensions.x-model-is-mutable}}{{>visibility}}{{/model.vendorExtensions.x-model-is-mutable}}{{^model.vendorExtensions.x-model-is-mutable}}internal{{/model.vendorExtensions.x-model-is-mutable}} {{classname}}({{#lambda.joinWithComma}}{{{dataType}}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{#model.composedSchemas.anyOf}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalProperty}}{{^required}}>{{/required}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{baseType}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{/model.composedSchemas.anyOf}}{{>ModelSignature}}{{/lambda.joinWithComma}}){{#parent}} : base({{#lambda.joinWithComma}}{{#parentModel.composedSchemas.oneOf}}{{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{parent}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}.{{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}} {{/parentModel.composedSchemas.oneOf}}{{>ModelBaseSignature}}{{/lambda.joinWithComma}}){{/parent}} + {{#model.vendorExtensions.x-model-is-mutable}}{{>visibility}}{{/model.vendorExtensions.x-model-is-mutable}}{{^model.vendorExtensions.x-model-is-mutable}}internal{{/model.vendorExtensions.x-model-is-mutable}} {{classname}}({{#lambda.joinWithComma}}{{{dataType}}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{#model.composedSchemas.anyOf}}{{{dataType}}}{{>NullConditionalProperty}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{baseType}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{/model.composedSchemas.anyOf}}{{>ModelSignature}}{{/lambda.joinWithComma}}){{#parent}} : base({{#lambda.joinWithComma}}{{#parentModel.composedSchemas.oneOf}}{{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{parent}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}.{{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}} {{/parentModel.composedSchemas.oneOf}}{{>ModelBaseSignature}}{{/lambda.joinWithComma}}){{/parent}} { {{#composedSchemas.anyOf}} - {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/composedSchemas.anyOf}} {{name}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{#allVars}} {{^isDiscriminator}} {{^isInherited}} - {{name}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{name}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/isInherited}} {{#isInherited}} {{#isNew}} - {{name}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{name}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/isNew}} {{/isInherited}} {{/isDiscriminator}} @@ -62,19 +62,19 @@ {{^composedSchemas.anyOf}} [JsonConstructor] {{/composedSchemas.anyOf}} - {{#model.vendorExtensions.x-model-is-mutable}}{{>visibility}}{{/model.vendorExtensions.x-model-is-mutable}}{{^model.vendorExtensions.x-model-is-mutable}}internal{{/model.vendorExtensions.x-model-is-mutable}} {{classname}}({{#lambda.joinWithComma}}{{#composedSchemas.anyOf}}{{^required}}Option<{{/required}}{{{baseType}}}{{>NullConditionalProperty}}{{^required}}>{{/required}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{/composedSchemas.anyOf}}{{>ModelSignature}}{{/lambda.joinWithComma}}){{#parent}} : base({{#lambda.joinWithComma}}{{>ModelBaseSignature}}{{/lambda.joinWithComma}}){{/parent}} + {{#model.vendorExtensions.x-model-is-mutable}}{{>visibility}}{{/model.vendorExtensions.x-model-is-mutable}}{{^model.vendorExtensions.x-model-is-mutable}}internal{{/model.vendorExtensions.x-model-is-mutable}} {{classname}}({{#lambda.joinWithComma}}{{#composedSchemas.anyOf}}{{{baseType}}}{{>NullConditionalProperty}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}} {{/composedSchemas.anyOf}}{{>ModelSignature}}{{/lambda.joinWithComma}}){{#parent}} : base({{#lambda.joinWithComma}}{{>ModelBaseSignature}}{{/lambda.joinWithComma}}){{/parent}} { {{#composedSchemas.anyOf}} - {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/composedSchemas.anyOf}} {{#allVars}} {{^isDiscriminator}} {{^isInherited}} - {{name}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{name}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/isInherited}} {{#isInherited}} {{#isNew}} - {{name}}{{^required}}Option{{/required}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; + {{name}} = {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}; {{/isNew}} {{/isInherited}} {{/isDiscriminator}} @@ -107,15 +107,7 @@ {{/isEnum}} {{^isDiscriminator}} {{#isEnum}} - {{^required}} - /// - /// Used to track the state of {{{name}}} - /// - [JsonIgnore] - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - public {{#isNew}}new {{/isNew}}Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}> {{name}}Option { get; {{^isReadOnly}}private set; {{/isReadOnly}}} - {{/required}} /// /// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}} /// @@ -129,22 +121,14 @@ {{#deprecated}} [Obsolete] {{/deprecated}} - public {{#isNew}}new {{/isNew}}{{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}}Option; } {{^isReadOnly}}set { this.{{name}}Option = new{{^net70OrLater}} Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}>{{/net70OrLater}}(value); } {{/isReadOnly}}}{{/required}} + public {{#isNew}}new {{/isNew}}{{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}}; } {{^isReadOnly}}set { this.{{name}} = value; } {{/isReadOnly}}}{{/required}} {{/isEnum}} {{/isDiscriminator}} {{/vars}} {{#composedSchemas.anyOf}} {{^vendorExtensions.x-duplicated-data-type}} - {{^required}} - /// - /// Used to track the state of {{{name}}} - /// - [JsonIgnore] - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - public {{#isNew}}new {{/isNew}}Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}> {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}Option { get; {{^isReadOnly}}private set; {{/isReadOnly}}} - {{/required}} /// /// {{description}}{{^description}}Gets or Sets {{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}{{/description}} /// {{#description}} @@ -155,7 +139,7 @@ {{#deprecated}} [Obsolete] {{/deprecated}} - public {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}Option; } {{^isReadOnly}}set { this.{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}Option = new{{^net70OrLater}} Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}>{{/net70OrLater}}(value); } {{/isReadOnly}}}{{/required}} + public {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}; } {{^isReadOnly}}set { this.{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}} = value; } {{/isReadOnly}}}{{/required}} {{/vendorExtensions.x-duplicated-data-type}} {{/composedSchemas.anyOf}} @@ -193,15 +177,7 @@ {{^isEnum}} {{#isInherited}} {{#isNew}} - {{^required}} - /// - /// Used to track the state of {{{name}}} - /// - [JsonIgnore] - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - public new Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}> {{name}}Option { get; {{^isReadOnly}}private set; {{/isReadOnly}}} - {{/required}} /// /// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}} /// {{#description}} @@ -213,20 +189,12 @@ {{#deprecated}} [Obsolete] {{/deprecated}} - public new {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}}Option } {{^isReadOnly}}set { this.{{name}}Option = new{{^net70OrLater}} Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}>{{/net70OrLater}}(value); } {{/isReadOnly}}}{{/required}} + public new {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}} } {{^isReadOnly}}set { this.{{name}} = value; } {{/isReadOnly}}}{{/required}} {{/isNew}} {{/isInherited}} {{^isInherited}} - {{^required}} - /// - /// Used to track the state of {{{name}}} - /// - [JsonIgnore] - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - public Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}> {{name}}Option { get; {{^isReadOnly}}private set; {{/isReadOnly}}} - {{/required}} /// /// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}} /// {{#description}} @@ -238,7 +206,7 @@ {{#deprecated}} [Obsolete] {{/deprecated}} - public {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}}Option; } {{^isReadOnly}}set { this.{{name}}Option = new{{^net70OrLater}} Option<{{{datatypeWithEnum}}}{{>NullConditionalProperty}}>{{/net70OrLater}}(value); } {{/isReadOnly}}}{{/required}} + public {{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}} {{/required}}{{/lambda.first}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}} {{/isInherited}} {{/isEnum}} From 6c385e7261a9f7ced29de97fb83101819ef9b802 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 26 May 2025 15:14:27 +0800 Subject: [PATCH 2/8] Change AddApi to Add{{clientName}} --- .../generichost/IHostBuilderExtensions.mustache | 4 ++-- .../generichost/IServiceCollectionExtensions.mustache | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IHostBuilderExtensions.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IHostBuilderExtensions.mustache index 948f06648ce1..05c117dfc8ab 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IHostBuilderExtensions.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IHostBuilderExtensions.mustache @@ -26,7 +26,7 @@ namespace {{packageName}}.Extensions { HostConfiguration config = new HostConfiguration(services); - IServiceCollectionExtensions.Add{{apiName}}(services, config); + IServiceCollectionExtensions.Add{{clientName}}(services, config); }); return builder; @@ -46,7 +46,7 @@ namespace {{packageName}}.Extensions options(context, services, config); - IServiceCollectionExtensions.Add{{apiName}}(services, config); + IServiceCollectionExtensions.Add{{clientName}}(services, config); }); return builder; diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IServiceCollectionExtensions.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IServiceCollectionExtensions.mustache index 14184ac4a22e..a07deae98834 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IServiceCollectionExtensions.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IServiceCollectionExtensions.mustache @@ -20,10 +20,10 @@ namespace {{packageName}}.Extensions /// Add the api to your host builder. /// /// - public static void Add{{apiName}}(this IServiceCollection services) + public static void Add{{clientName}}(this IServiceCollection services) { HostConfiguration config = new{{^net70OrLater}} HostConfiguration{{/net70OrLater}}(services); - Add{{apiName}}(services, config); + Add{{clientName}}(services, config); } {{/hasAuthMethods}} @@ -32,14 +32,14 @@ namespace {{packageName}}.Extensions /// /// /// - public static void Add{{apiName}}(this IServiceCollection services, Action options) + public static void Add{{clientName}}(this IServiceCollection services, Action options) { HostConfiguration config = new{{^net70OrLater}} HostConfiguration{{/net70OrLater}}(services); options(config); - Add{{apiName}}(services, config); + Add{{clientName}}(services, config); } - internal static void Add{{apiName}}(IServiceCollection services, HostConfiguration host) + internal static void Add{{clientName}}(IServiceCollection services, HostConfiguration host) { if (!host.HttpClientsAdded) host.Add{{apiName}}HttpClients(); From 1bc8d6853b500d37fee0001dea33d9397cc3111b Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 3 Jun 2025 09:26:07 +0800 Subject: [PATCH 3/8] Use JsonSerializerOptions instead of JsonSerializerOptionsProvider Apply nullable enum in constructor --- .../csharp/libraries/generichost/IApi.mustache | 11 ++++++----- .../libraries/generichost/ModelSignature.mustache | 2 +- .../csharp/libraries/generichost/api.mustache | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache index cc978d7b1de2..de683269207a 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache @@ -1,4 +1,5 @@ using System.Net.Http; +using System.Text.Json; using {{packageName}}.{{clientPackage}}; using {{packageName}}.{{apiPackage}}; @@ -19,7 +20,7 @@ namespace {{packageName}}.{{apiPackage}} /// public partial interface {{interfacePrefix}}{{clientName}} { - JsonSerializerOptionsProvider JsonSerializerOptionsProvider { get; } + JsonSerializerOptions JsonSerializerOptions { get; } {{#apiInfo.apis}} {{interfacePrefix}}{{baseName}} {{baseName}} { get; } @@ -33,18 +34,18 @@ namespace {{packageName}} public class {{clientName}} : {{interfacePrefix}}{{clientName}} { public HttpClient HttpClient { get; } - public JsonSerializerOptionsProvider JsonSerializerOptionsProvider { get; private set; } + public JsonSerializerOptions JsonSerializerOptions { get; private set; } {{#apiInfo.apis}} {{>visibility}} virtual {{interfacePrefix}}{{baseName}} {{baseName}} { get; private set; } {{/apiInfo.apis}} public {{clientName}}( - HttpClient httpClient, JsonSerializerOptionsProvider jsonSerializerOptionsProvider) + HttpClient httpClient, JsonSerializerOptions jsonSerializerOptions) { HttpClient = httpClient; - JsonSerializerOptionsProvider = jsonSerializerOptionsProvider; + JsonSerializerOptions = jsonSerializerOptions; {{#apiInfo.apis}} - {{baseName}} = new {{baseName}}(httpClient, jsonSerializerOptionsProvider); + {{baseName}} = new {{baseName}}(httpClient, jsonSerializerOptions); {{/apiInfo.apis}} } diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache index d5cf70bd67fa..3a6c4ace911b 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ModelSignature.mustache @@ -1 +1 @@ -{{#model.allVars}}{{^isDiscriminator}}{{{datatypeWithEnum}}}{{#isNullable}}{{>NullConditionalProperty}}{{/isNullable}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}{{#defaultValue}} = {{^required}}default{{/required}}{{#required}}{{^isDateTime}}{{#isString}}{{^isEnum}}@{{/isEnum}}{{/isString}}{{{.}}}{{/isDateTime}}{{#isDateTime}}default{{/isDateTime}}{{/required}}{{/defaultValue}}{{^defaultValue}}{{#lambda.first}}{{#isNullable}} = default {{/isNullable}}{{^required}} = default {{/required}}{{/lambda.first}}{{/defaultValue}} {{/isDiscriminator}}{{/model.allVars}} +{{#model.allVars}}{{^isDiscriminator}}{{{datatypeWithEnum}}}{{#isEnum}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}}{{/isEnum}}{{^isEnum}}{{#isNullable}}{{>NullConditionalProperty}}{{/isNullable}}{{/isEnum}} {{#lambda.escape_reserved_word}}{{#lambda.camel_case}}{{name}}{{/lambda.camel_case}}{{/lambda.escape_reserved_word}}{{#defaultValue}} = {{^required}}default{{/required}}{{#required}}{{^isDateTime}}{{#isString}}{{^isEnum}}@{{/isEnum}}{{/isString}}{{{.}}}{{/isDateTime}}{{#isDateTime}}default{{/isDateTime}}{{/required}}{{/defaultValue}}{{^defaultValue}}{{#lambda.first}}{{#isNullable}} = default {{/isNullable}}{{^required}}{{#isEnum}} = null{{/isEnum}}{{^isEnum}} = default{{/isEnum}} {{/required}}{{/lambda.first}}{{/defaultValue}} {{/isDiscriminator}}{{/model.allVars}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache index 0191b0df2228..870956da07ac 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache @@ -151,7 +151,7 @@ namespace {{packageName}} /// Initializes a new instance of the class. /// /// - public {{baseName}}(HttpClient httpClient, JsonSerializerOptionsProvider jsonSerializerOptionsProvider {{#hasApiKeyMethods}}, + public {{baseName}}(HttpClient httpClient, JsonSerializerOptions jsonSerializerOptions {{#hasApiKeyMethods}}, TokenProvider apiKeyProvider{{/hasApiKeyMethods}}{{#hasHttpBearerMethods}}, TokenProvider bearerTokenProvider{{/hasHttpBearerMethods}}{{#hasHttpBasicMethods}}, TokenProvider basicTokenProvider{{/hasHttpBasicMethods}}{{#hasHttpSignatureMethods}}, @@ -159,7 +159,7 @@ namespace {{packageName}} TokenProvider oauthTokenProvider{{/hasOAuthMethods}}{{#net80OrLater}}{{#operation}}{{#lambda.uniqueLines}}{{#vendorExtensions.x-set-cookie}}, {{packageName}}.{{clientPackage}}.CookieContainer cookieContainer{{/vendorExtensions.x-set-cookie}}{{/lambda.uniqueLines}}{{/operation}}{{/net80OrLater}}) { - _jsonSerializerOptions = jsonSerializerOptionsProvider.Options; + _jsonSerializerOptions = jsonSerializerOptions; HttpClient = httpClient;{{#hasApiKeyMethods}} ApiKeyProvider = apiKeyProvider;{{/hasApiKeyMethods}}{{#hasHttpBearerMethods}} BearerTokenProvider = bearerTokenProvider;{{/hasHttpBearerMethods}}{{#hasHttpBasicMethods}} From 5e5a00151965fdc65248493c6b4dffc09c060e79 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 3 Jun 2025 13:20:49 +0800 Subject: [PATCH 4/8] Update getter and setter for models. --- .../csharp/libraries/generichost/modelGeneric.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache index 1e12f610cfc0..9cefac24dde5 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache @@ -121,7 +121,7 @@ {{#deprecated}} [Obsolete] {{/deprecated}} - public {{#isNew}}new {{/isNew}}{{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} {{#required}}{ get; {{^isReadOnly}}set; {{/isReadOnly}}}{{/required}}{{^required}}{ get { return this.{{name}}; } {{^isReadOnly}}set { this.{{name}} = value; } {{/isReadOnly}}}{{/required}} + public {{#isNew}}new {{/isNew}}{{{datatypeWithEnum}}}{{#lambda.first}}{{#isNullable}}{{>NullConditionalProperty}} {{/isNullable}}{{^required}}{{nrt?}}{{^nrt}}{{#vendorExtensions.x-is-value-type}}?{{/vendorExtensions.x-is-value-type}}{{/nrt}} {{/required}}{{/lambda.first}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}} {{/isEnum}} {{/isDiscriminator}} From c072c40faa0903c3ec24be7ab27016a91090371d Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 17 Jun 2025 15:32:55 +0800 Subject: [PATCH 5/8] Fix DateOnly converter. Inject JsonSerializerOptions. --- .../csharp/libraries/generichost/ClientUtils.mustache | 7 +++++++ .../csharp/libraries/generichost/DateFormats.mustache | 2 +- .../libraries/generichost/DateOnlyJsonConverter.mustache | 2 +- .../generichost/DateOnlyNullableJsonConverter.mustache | 2 +- .../libraries/generichost/HostConfiguration.mustache | 5 ++++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ClientUtils.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ClientUtils.mustache index 357d2197cd97..892fb558906d 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ClientUtils.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ClientUtils.mustache @@ -209,6 +209,13 @@ using System.Runtime.CompilerServices; entries.Add(ParameterToString(entry)); return string.Join(",", entries); } + else if (obj is IEnumerable enumerable) + { + List entries = new{{^net70OrLater}} List{{/net70OrLater}}(); + foreach (var entry in enumerable) + entries.Add(ParameterToString(entry)); + return string.Join(",", entries); + } return Convert.ToString(obj, System.Globalization.CultureInfo.InvariantCulture); } diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateFormats.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateFormats.mustache index 920ecda88fad..d3064c29d0ec 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateFormats.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateFormats.mustache @@ -1,2 +1,2 @@ - "yyyy'-'MM'-'dd", + "yyyy-MM-dd", "yyyyMMdd" diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyJsonConverter.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyJsonConverter.mustache index 209979c8db42..095b05d2fa07 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyJsonConverter.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyJsonConverter.mustache @@ -33,7 +33,7 @@ namespace {{packageName}}.{{clientPackage}} string value = reader.GetString(){{nrt!}}; foreach(string format in Formats) - if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result)) + if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly result)) return result; throw new NotSupportedException(); diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyNullableJsonConverter.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyNullableJsonConverter.mustache index 17c847365369..8608ae50635e 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyNullableJsonConverter.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/DateOnlyNullableJsonConverter.mustache @@ -33,7 +33,7 @@ namespace {{packageName}}.{{clientPackage}} string value = reader.GetString(){{nrt!}}; foreach(string format in Formats) - if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result)) + if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly result)) return result; throw new NotSupportedException(); diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache index 13a784d4aef1..97e4731ef16a 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/HostConfiguration.mustache @@ -16,6 +16,7 @@ using {{packageName}}.{{apiPackage}}; using {{packageName}}.{{modelPackage}}; {{/-first}} {{/models}} +using System.Text.Json.Serialization.Metadata; namespace {{packageName}}.{{clientPackage}} { @@ -43,10 +44,12 @@ namespace {{packageName}}.{{clientPackage}} _jsonOptions.Converters.Add(new DateOnlyJsonConverter()); _jsonOptions.Converters.Add(new DateOnlyNullableJsonConverter()); {{/supportsDateOnly}} + _jsonOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver(); JsonSerializerOptionsProvider jsonSerializerOptionsProvider = new{{^net60OrLater}} JsonSerializerOptionsProvider{{/net60OrLater}}(_jsonOptions); _services.AddSingleton(jsonSerializerOptionsProvider); - {{#useSourceGeneration}} + _services.AddSingleton(jsonSerializerOptionsProvider.Options); + {{#useSourceGeneration}} {{#models}} {{#-first}} From bb0649ef7ececd5523a6365e73bf3074a3510a20 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 18 Jun 2025 17:43:38 +0800 Subject: [PATCH 6/8] Add JsonSerializerContext for supporting AOT --- .../csharp/libraries/generichost/IApi.mustache | 16 ++++++++++++++++ .../generichost/README.client.mustache | 17 +++++++++-------- .../csharp/libraries/generichost/api.mustache | 4 ++++ .../libraries/generichost/modelGeneric.mustache | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache index de683269207a..6e0de6c3dc98 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache @@ -1,5 +1,8 @@ +using System; +using System.Collections.Generic; using System.Net.Http; using System.Text.Json; +using System.Text.Json.Serialization; using {{packageName}}.{{clientPackage}}; using {{packageName}}.{{apiPackage}}; @@ -50,4 +53,17 @@ namespace {{packageName}} } } +} +namespace {{packageName}}.Models +{ + /// + /// + /// + public static class GlobalContext + { + /// + /// + /// + public static Dictionary ContextMapper = new Dictionary(); + } } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache index 7f864db5fd92..cbdffb5d819f 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/README.client.mustache @@ -50,9 +50,8 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; -using {{packageName}}.Api; -using {{packageName}}.Client; -using {{packageName}}.Model; +using {{packageName}}.Extensions; +using {{packageName}}.Interfaces; namespace YourProject { @@ -61,13 +60,13 @@ namespace YourProject public static async Task Main(string[] args) { var host = CreateHostBuilder(args).Build();{{#apiInfo}}{{#apis}}{{#-first}} - var api = host.Services.GetRequiredService<{{interfacePrefix}}{{classname}}>(); + var api = host.Services.GetRequiredService<{{interfacePrefix}}{{clientName}}>(); {{#operations}} {{#-first}} {{#operation}} {{#-first}} - {{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}ApiResponse apiResponse = await api.{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async("todo"); - {{#returnType}}{{{.}}}{{/returnType}}{{^returnType}}object{{/returnType}} model = apiResponse.Ok(); + var apiResponse = await api.{{baseName}}.{{#vendorExtensions.x-csharp-operationId}}{{vendorExtensions.x-csharp-operationId}}{{/vendorExtensions.x-csharp-operationId}}{{^vendorExtensions.x-csharp-operationId}}{{operationId}}{{/vendorExtensions.x-csharp-operationId}}Async("todo"); + Console.WriteLine($"Response: {apiResponse.ToString()}"); {{/-first}} {{/operation}} {{/-first}} @@ -78,7 +77,7 @@ namespace YourProject } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) - .Configure{{apiName}}((context, options) => + .Configure{{apiName}}((context, services, options) => { {{#authMethods}} {{#-first}} @@ -96,7 +95,9 @@ namespace YourProject // your custom converters if any }); - options.Add{{apiName}}HttpClients(builder: builder => builder + options.Add{{apiName}}HttpClients( + client: client => client.BaseAddress = new Uri(context.Configuration["ApiSettings:BaseAddress"]), + builder: builder => builder .AddRetryPolicy(2) .AddTimeoutPolicy(TimeSpan.FromSeconds(5)) .AddCircuitBreakerPolicy(10, TimeSpan.FromSeconds(30)) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache index 870956da07ac..4b84e3defbca 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache @@ -535,6 +535,10 @@ namespace {{packageName}} {{/vendorExtensions.x-set-cookie}} {{/responses}} {{/net80OrLater}} + {{#returnType}}{{^returnTypeIsPrimitive}} + {{returnBaseType}}.ClassInit = true; + _jsonSerializerOptions.TypeInfoResolver = GlobalContext.ContextMapper[typeof({{{returnType}}})]; + {{/returnTypeIsPrimitive}}{{/returnType}} return new HttpOperationResponse{{#returnType}}<{{{returnType}}}>{{/returnType}} { {{#returnType}}Body = JsonSerializer.Deserialize<{{{returnType}}}>(responseContentLocalVar, _jsonSerializerOptions),{{/returnType}} diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache index 9cefac24dde5..8fafca615d11 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/modelGeneric.mustache @@ -1,3 +1,13 @@ + [JsonSerializable(typeof({{classname}}))] + internal partial class {{classname}}Context : JsonSerializerContext + { + } + [JsonSerializable(typeof(IEnumerable<{{classname}}>))] + internal partial class IEnumerable{{classname}}Context : JsonSerializerContext + { + + } + /// /// {{description}}{{^description}}{{classname}}{{/description}} /// @@ -47,6 +57,13 @@ {{/vendorExtensions.x-duplicated-data-type}} {{/composedSchemas.oneOf}} + static {{classname}}() + { + GlobalContext.ContextMapper.Add(typeof({{classname}}), {{classname}}Context.Default); + GlobalContext.ContextMapper.Add(typeof(IEnumerable<{{classname}}>), IEnumerable{{classname}}Context.Default); + } + public static bool ClassInit = false; + {{^composedSchemas.oneOf}} /// /// Initializes a new instance of the class. From 44805fad7d37f8ce73d439c3b724b75090d12704 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 4 Jul 2025 11:09:36 +0800 Subject: [PATCH 7/8] Update api template for array query params, empty query params, AOT json serializer resolver, and enum in serialization. --- .../csharp/libraries/generichost/api.mustache | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache index 4b84e3defbca..5f59468e9869 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache @@ -307,19 +307,39 @@ namespace {{packageName}} {{/isApiKey}} {{/authMethods}} {{/queryParams}} + string paramValue = ""; {{#queryParams}} {{#required}} {{#-first}} {{/-first}} {{/required}} - parseQueryStringLocalVar["{{baseName}}"] = ClientUtils.ParameterToString({{paramName}}); + {{#isArray}} + foreach (var item in {{paramName}}) + { + var value = ClientUtils.ParameterToString(item); + if (!string.IsNullOrEmpty(value)) + { + parseQueryStringLocalVar["{{baseName}}"] = value; + } + } + {{/isArray}} + {{^isArray}} + paramValue = ClientUtils.ParameterToString({{paramName}}); + if (!string.IsNullOrEmpty(paramValue)) + { + parseQueryStringLocalVar["{{baseName}}"] = paramValue; + } + {{/isArray}} {{/queryParams}} - {{#constantParams}} {{#isQueryParam}} // Set client side default value of Query Param "{{baseName}}". - parseQueryStringLocalVar["{{baseName}}"] = ClientUtils.ParameterToString({{#_enum}}"{{{.}}}"{{/_enum}}); // Constant query parameter + paramValue = ClientUtils.ParameterToString({{#_enum}}"{{{.}}}"{{/_enum}}); // Constant query parameter + if (!string.IsNullOrEmpty(paramValue)) + { + parseQueryStringLocalVar["{{baseName}}"] = paramValue; + } {{/isQueryParam}} {{/constantParams}} {{#queryParams}} @@ -535,13 +555,15 @@ namespace {{packageName}} {{/vendorExtensions.x-set-cookie}} {{/responses}} {{/net80OrLater}} - {{#returnType}}{{^returnTypeIsPrimitive}} + + JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions(_jsonSerializerOptions); + {{#returnType}}{{^returnTypeIsPrimitive}}{{^returnProperty.mostInnerItems.isEnumRef}} {{returnBaseType}}.ClassInit = true; - _jsonSerializerOptions.TypeInfoResolver = GlobalContext.ContextMapper[typeof({{{returnType}}})]; - {{/returnTypeIsPrimitive}}{{/returnType}} + jsonSerializerOptions.TypeInfoResolver = GlobalContext.ContextMapper[typeof({{{returnType}}})]; + {{/returnProperty.mostInnerItems.isEnumRef}}{{/returnTypeIsPrimitive}}{{/returnType}} return new HttpOperationResponse{{#returnType}}<{{{returnType}}}>{{/returnType}} { - {{#returnType}}Body = JsonSerializer.Deserialize<{{{returnType}}}>(responseContentLocalVar, _jsonSerializerOptions),{{/returnType}} + {{#returnType}}Body = JsonSerializer.Deserialize<{{{returnType}}}>(responseContentLocalVar, jsonSerializerOptions),{{/returnType}} Request = httpRequestMessageLocalVar, Response = httpResponseMessageLocalVar }; From fc8dedc9839bcbcb9af6bbcfa846fd2aea09d0e0 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 18 Aug 2025 09:45:54 +0800 Subject: [PATCH 8/8] update ctor parameter of client --- .../csharp/libraries/generichost/IApi.mustache | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache index 6e0de6c3dc98..47e71a9de6f3 100644 --- a/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/IApi.mustache @@ -43,12 +43,24 @@ namespace {{packageName}} {{/apiInfo.apis}} public {{clientName}}( - HttpClient httpClient, JsonSerializerOptions jsonSerializerOptions) + HttpClient httpClient, JsonSerializerOptions? jsonSerializerOptions = null) { HttpClient = httpClient; - JsonSerializerOptions = jsonSerializerOptions; + if (jsonSerializerOptions != null) + { + JsonSerializerOptions = jsonSerializerOptions; + } + else + { + JsonSerializerOptions = new JsonSerializerOptions(); + JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter()); + JsonSerializerOptions.Converters.Add(new DateTimeNullableJsonConverter()); + JsonSerializerOptions.Converters.Add(new DateOnlyJsonConverter()); + JsonSerializerOptions.Converters.Add(new DateOnlyNullableJsonConverter()); + } {{#apiInfo.apis}} - {{baseName}} = new {{baseName}}(httpClient, jsonSerializerOptions); + {{baseName}} = new {{baseName}}(httpClient, JsonSerializerOptions); {{/apiInfo.apis}} }