Skip to content

Commit

Permalink
C# API Client CancellationToken, Base Validation and Nullable/Required (
Browse files Browse the repository at this point in the history
#13049)

* Ensure CancellationTokenSource disposal in CSharp clients

* Fixed broken BaseValidate in CSharp models

* Ensure final CancellationToken is used in CSharp API clients

* Ensure EmitDefaultValue true for required properties in CSharp clients

* Regenerated samples

* Fixed broken C# ApiClient.ExecAsync disposable resources
  • Loading branch information
krzlabrdx committed Aug 6, 2022
1 parent f5900c7 commit 641d515
Show file tree
Hide file tree
Showing 158 changed files with 450 additions and 399 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -448,84 +448,101 @@ namespace {{packageName}}.Client
IReadableConfiguration configuration,
System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
CancellationTokenSource timeoutTokenSource = null;
CancellationTokenSource finalTokenSource = null;
var deserializer = new CustomJsonCodec(SerializerSettings, configuration);
var finalToken = cancellationToken;
if (configuration.Timeout > 0)
try
{
var tokenSource = new CancellationTokenSource(configuration.Timeout);
finalToken = CancellationTokenSource.CreateLinkedTokenSource(finalToken, tokenSource.Token).Token;
}
if (configuration.Timeout > 0)
{
timeoutTokenSource = new CancellationTokenSource(configuration.Timeout);
finalTokenSource = CancellationTokenSource.CreateLinkedTokenSource(finalToken, timeoutTokenSource.Token);
finalToken = finalTokenSource.Token;
}

if (configuration.Proxy != null)
{
if(_httpClientHandler == null) throw new InvalidOperationException("Configuration `Proxy` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
_httpClientHandler.Proxy = configuration.Proxy;
}
if (configuration.Proxy != null)
{
if(_httpClientHandler == null) throw new InvalidOperationException("Configuration `Proxy` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
_httpClientHandler.Proxy = configuration.Proxy;
}

if (configuration.ClientCertificates != null)
{
if(_httpClientHandler == null) throw new InvalidOperationException("Configuration `ClientCertificates` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
_httpClientHandler.ClientCertificates.AddRange(configuration.ClientCertificates);
}
if (configuration.ClientCertificates != null)
{
if(_httpClientHandler == null) throw new InvalidOperationException("Configuration `ClientCertificates` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
_httpClientHandler.ClientCertificates.AddRange(configuration.ClientCertificates);
}

var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;
var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;

if (cookieContainer != null)
{
if(_httpClientHandler == null) throw new InvalidOperationException("Request property `CookieContainer` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
foreach (var cookie in cookieContainer)
if (cookieContainer != null)
{
_httpClientHandler.CookieContainer.Add(cookie);
if(_httpClientHandler == null) throw new InvalidOperationException("Request property `CookieContainer` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
foreach (var cookie in cookieContainer)
{
_httpClientHandler.CookieContainer.Add(cookie);
}
}
}

InterceptRequest(req);
InterceptRequest(req);

HttpResponseMessage response;
{{#supportsRetry}}
if (RetryConfiguration.AsyncRetryPolicy != null)
{
var policy = RetryConfiguration.AsyncRetryPolicy;
var policyResult = await policy
.ExecuteAndCaptureAsync(() => _httpClient.SendAsync(req, cancellationToken))
.ConfigureAwait(false);
response = (policyResult.Outcome == OutcomeType.Successful) ?
policyResult.Result : new HttpResponseMessage()
{
ReasonPhrase = policyResult.FinalException.ToString(),
RequestMessage = req
};
}
else
{
{{/supportsRetry}}
response = await _httpClient.SendAsync(req, cancellationToken).ConfigureAwait(false);
{{#supportsRetry}}
}
{{/supportsRetry}}
HttpResponseMessage response;
{{#supportsRetry}}
if (RetryConfiguration.AsyncRetryPolicy != null)
{
var policy = RetryConfiguration.AsyncRetryPolicy;
var policyResult = await policy
.ExecuteAndCaptureAsync(() => _httpClient.SendAsync(req, finalToken))
.ConfigureAwait(false);
response = (policyResult.Outcome == OutcomeType.Successful) ?
policyResult.Result : new HttpResponseMessage()
{
ReasonPhrase = policyResult.FinalException.ToString(),
RequestMessage = req
};
}
else
{
{{/supportsRetry}}
response = await _httpClient.SendAsync(req, finalToken).ConfigureAwait(false);
{{#supportsRetry}}
}
{{/supportsRetry}}

if (!response.IsSuccessStatusCode)
{
return await ToApiResponse<T>(response, default(T), req.RequestUri);
}

object responseData = await deserializer.Deserialize<T>(response);
if (!response.IsSuccessStatusCode)
{
return await ToApiResponse<T>(response, default(T), req.RequestUri);
}

// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
{
responseData = (T) typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content });
object responseData = await deserializer.Deserialize<T>(response);

// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
{
responseData = (T) typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content });
}
else if (typeof(T).Name == "Stream") // for binary response
{
responseData = (T) (object) await response.Content.ReadAsStreamAsync();
}

InterceptResponse(req, response);

return await ToApiResponse<T>(response, responseData, req.RequestUri);
}
else if (typeof(T).Name == "Stream") // for binary response
finally
{
responseData = (T) (object) await response.Content.ReadAsStreamAsync();
}

InterceptResponse(req, response);
if (timeoutTokenSource != null)
{
timeoutTokenSource.Dispose();
}

return await ToApiResponse<T>(response, responseData, req.RequestUri);
if (finalTokenSource != null)
{
finalTokenSource.Dispose();
}
}
}

{{#supportsAsync}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
/// <value>{{description}}</value>
{{/description}}
{{^conditionalSerialization}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
public {{#complexType}}{{{complexType}}}{{/complexType}}{{^complexType}}{{{datatypeWithEnum}}}{{/complexType}}{{^isContainer}}{{^required}}?{{/required}}{{/isContainer}} {{name}} { get; set; }
{{#isReadOnly}}

Expand All @@ -48,7 +48,7 @@
{{/conditionalSerialization}}
{{#conditionalSerialization}}
{{#isReadOnly}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
public {{#complexType}}{{{complexType}}}{{/complexType}}{{^complexType}}{{{datatypeWithEnum}}}{{/complexType}}{{^isContainer}}{{^required}}?{{/required}}{{/isContainer}} {{name}} { get; set; }


Expand All @@ -63,7 +63,7 @@
{{/isReadOnly}}

{{^isReadOnly}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
public {{#complexType}}{{{complexType}}}{{/complexType}}{{^complexType}}{{{datatypeWithEnum}}}{{/complexType}}{{^isContainer}}{{^required}}?{{/required}}{{/isContainer}} {{name}}
{
get{ return _{{name}};}
Expand Down Expand Up @@ -180,7 +180,7 @@
/// </summary>{{#description}}
/// <value>{{description}}</value>{{/description}}
{{^conditionalSerialization}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
{{#isDate}}
[JsonConverter(typeof(OpenAPIDateConverter))]
{{/isDate}}
Expand All @@ -199,7 +199,7 @@
{{/conditionalSerialization}}
{{#conditionalSerialization}}
{{#isReadOnly}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
{{#isDate}}
[JsonConverter(typeof(OpenAPIDateConverter))]
{{/isDate}}
Expand All @@ -218,7 +218,7 @@
{{#isDate}}
[JsonConverter(typeof(OpenAPIDateConverter))]
{{/isDate}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/vendorExtensions.x-emit-default-value}})]
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
public {{{dataType}}} {{name}}
{
get{ return _{{name}};}
Expand Down Expand Up @@ -397,7 +397,7 @@
{{#parent}}
{{^isArray}}
{{^isMap}}
foreach(var x in BaseValidate(validationContext)) yield return x;
foreach(var x in {{#discriminator}}base.{{/discriminator}}BaseValidate(validationContext)) yield return x;
{{/isMap}}
{{/isArray}}
{{/parent}}
Expand Down
Loading

0 comments on commit 641d515

Please sign in to comment.