Skip to content

Commit af94bde

Browse files
authored
#19176 fix Task.Result directly blocks thread (#19231)
- async should never be blocked on the ApiClient To fix we invert the logic and use Task as base and keep consistency, we expect and wait result only on synchronous calls.
1 parent 2c2d690 commit af94bde

12 files changed

Lines changed: 208 additions & 268 deletions

File tree

  • modules/openapi-generator/src/main/resources/csharp
  • samples/client
    • echo_api/csharp-restsharp/src/Org.OpenAPITools/Client
    • others/csharp-complex-files/src/Org.OpenAPITools/Client
    • petstore/csharp/restsharp

modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,9 @@ namespace {{packageName}}.Client
449449
/// <param name="configuration">A per-request configuration object.
450450
/// It is assumed that any merge with GlobalConfiguration has been done before calling this method.</param>
451451
/// <returns>A new ApiResponse instance.</returns>
452-
private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
452+
private async Task<ApiResponse<T>> ExecClientAsync<T>(Func<RestClient, Task<RestResponse<T>>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
453453
{
454454
var baseUrl = configuration.GetOperationServerUrl(options.Operation, options.OperationIndex) ?? _baseUrl;
455-
456455
var clientOptions = new RestClientOptions(baseUrl)
457456
{
458457
ClientCertificates = configuration.ClientCertificates,
@@ -486,7 +485,7 @@ namespace {{packageName}}.Client
486485
{
487486
InterceptRequest(request);
488487
489-
RestResponse<T> response = getResponse(client);
488+
RestResponse<T> response = await getResponse(client);
490489
491490
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
492491
if (typeof(AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
@@ -582,21 +581,21 @@ namespace {{packageName}}.Client
582581
clientOptions.CookieContainer = cookies;
583582
};
584583
585-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
584+
Func<RestClient, Task<RestResponse<T>>> getResponse = (client) =>
586585
{
587586
if (RetryConfiguration.RetryPolicy != null)
588587
{
589588
var policy = RetryConfiguration.RetryPolicy;
590589
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
591-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
590+
return Task.FromResult(DeserializeRestResponseFromPolicy<T>(client, request, policyResult));
592591
}
593592
else
594593
{
595-
return client.Execute<T>(request);
594+
return Task.FromResult(client.Execute<T>(request));
596595
}
597596
};
598597
599-
return ExecClient(getResponse, setOptions, request, options, configuration);
598+
return ExecClientAsync(getResponse, setOptions, request, options, configuration).GetAwaiter().GetResult();
600599
}
601600
602601
{{#supportsAsync}}
@@ -607,29 +606,25 @@ namespace {{packageName}}.Client
607606
//no extra options
608607
};
609608
610-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
609+
Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
611610
{
612-
Func<Task<RestResponse<T>>> action = async () =>
611+
{{#supportsRetry}}
612+
if (RetryConfiguration.AsyncRetryPolicy != null)
613613
{
614-
{{#supportsRetry}}
615-
if (RetryConfiguration.AsyncRetryPolicy != null)
616-
{
617-
var policy = RetryConfiguration.AsyncRetryPolicy;
618-
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
619-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
620-
}
621-
else
622-
{
623-
{{/supportsRetry}}
624-
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
625-
{{#supportsRetry}}
626-
}
627-
{{/supportsRetry}}
628-
};
629-
return action().Result;
614+
var policy = RetryConfiguration.AsyncRetryPolicy;
615+
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
616+
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
617+
}
618+
else
619+
{
620+
{{/supportsRetry}}
621+
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
622+
{{#supportsRetry}}
623+
}
624+
{{/supportsRetry}}
630625
};
631626
632-
return Task.FromResult<ApiResponse<T>>(ExecClient(getResponse, setOptions, request, options, configuration));
627+
return ExecClientAsync(getResponse, setOptions, request, options, configuration);
633628
}
634629
635630
#region IAsynchronousClient

samples/client/echo_api/csharp-restsharp/src/Org.OpenAPITools/Client/ApiClient.cs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,9 @@ private ApiResponse<T> ToApiResponse<T>(RestResponse<T> response)
449449
/// <param name="configuration">A per-request configuration object.
450450
/// It is assumed that any merge with GlobalConfiguration has been done before calling this method.</param>
451451
/// <returns>A new ApiResponse instance.</returns>
452-
private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
452+
private async Task<ApiResponse<T>> ExecClientAsync<T>(Func<RestClient, Task<RestResponse<T>>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
453453
{
454454
var baseUrl = configuration.GetOperationServerUrl(options.Operation, options.OperationIndex) ?? _baseUrl;
455-
456455
var clientOptions = new RestClientOptions(baseUrl)
457456
{
458457
ClientCertificates = configuration.ClientCertificates,
@@ -469,7 +468,7 @@ private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getRespon
469468
{
470469
InterceptRequest(request);
471470

472-
RestResponse<T> response = getResponse(client);
471+
RestResponse<T> response = await getResponse(client);
473472

474473
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
475474
if (typeof(AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
@@ -565,21 +564,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
565564
clientOptions.CookieContainer = cookies;
566565
};
567566

568-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
567+
Func<RestClient, Task<RestResponse<T>>> getResponse = (client) =>
569568
{
570569
if (RetryConfiguration.RetryPolicy != null)
571570
{
572571
var policy = RetryConfiguration.RetryPolicy;
573572
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
574-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
573+
return Task.FromResult(DeserializeRestResponseFromPolicy<T>(client, request, policyResult));
575574
}
576575
else
577576
{
578-
return client.Execute<T>(request);
577+
return Task.FromResult(client.Execute<T>(request));
579578
}
580579
};
581580

582-
return ExecClient(getResponse, setOptions, request, options, configuration);
581+
return ExecClientAsync(getResponse, setOptions, request, options, configuration).GetAwaiter().GetResult();
583582
}
584583

585584
private Task<ApiResponse<T>> ExecAsync<T>(RestRequest request, RequestOptions options, IReadableConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
@@ -589,25 +588,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
589588
//no extra options
590589
};
591590

592-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
591+
Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
593592
{
594-
Func<Task<RestResponse<T>>> action = async () =>
593+
if (RetryConfiguration.AsyncRetryPolicy != null)
595594
{
596-
if (RetryConfiguration.AsyncRetryPolicy != null)
597-
{
598-
var policy = RetryConfiguration.AsyncRetryPolicy;
599-
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
600-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
601-
}
602-
else
603-
{
604-
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
605-
}
606-
};
607-
return action().Result;
595+
var policy = RetryConfiguration.AsyncRetryPolicy;
596+
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
597+
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
598+
}
599+
else
600+
{
601+
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
602+
}
608603
};
609604

610-
return Task.FromResult<ApiResponse<T>>(ExecClient(getResponse, setOptions, request, options, configuration));
605+
return ExecClientAsync(getResponse, setOptions, request, options, configuration);
611606
}
612607

613608
#region IAsynchronousClient

samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Client/ApiClient.cs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,9 @@ private ApiResponse<T> ToApiResponse<T>(RestResponse<T> response)
449449
/// <param name="configuration">A per-request configuration object.
450450
/// It is assumed that any merge with GlobalConfiguration has been done before calling this method.</param>
451451
/// <returns>A new ApiResponse instance.</returns>
452-
private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
452+
private async Task<ApiResponse<T>> ExecClientAsync<T>(Func<RestClient, Task<RestResponse<T>>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
453453
{
454454
var baseUrl = configuration.GetOperationServerUrl(options.Operation, options.OperationIndex) ?? _baseUrl;
455-
456455
var clientOptions = new RestClientOptions(baseUrl)
457456
{
458457
ClientCertificates = configuration.ClientCertificates,
@@ -469,7 +468,7 @@ private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getRespon
469468
{
470469
InterceptRequest(request);
471470

472-
RestResponse<T> response = getResponse(client);
471+
RestResponse<T> response = await getResponse(client);
473472

474473
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
475474
if (typeof(AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
@@ -565,21 +564,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
565564
clientOptions.CookieContainer = cookies;
566565
};
567566

568-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
567+
Func<RestClient, Task<RestResponse<T>>> getResponse = (client) =>
569568
{
570569
if (RetryConfiguration.RetryPolicy != null)
571570
{
572571
var policy = RetryConfiguration.RetryPolicy;
573572
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
574-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
573+
return Task.FromResult(DeserializeRestResponseFromPolicy<T>(client, request, policyResult));
575574
}
576575
else
577576
{
578-
return client.Execute<T>(request);
577+
return Task.FromResult(client.Execute<T>(request));
579578
}
580579
};
581580

582-
return ExecClient(getResponse, setOptions, request, options, configuration);
581+
return ExecClientAsync(getResponse, setOptions, request, options, configuration).GetAwaiter().GetResult();
583582
}
584583

585584
private Task<ApiResponse<T>> ExecAsync<T>(RestRequest request, RequestOptions options, IReadableConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
@@ -589,25 +588,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
589588
//no extra options
590589
};
591590

592-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
591+
Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
593592
{
594-
Func<Task<RestResponse<T>>> action = async () =>
593+
if (RetryConfiguration.AsyncRetryPolicy != null)
595594
{
596-
if (RetryConfiguration.AsyncRetryPolicy != null)
597-
{
598-
var policy = RetryConfiguration.AsyncRetryPolicy;
599-
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
600-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
601-
}
602-
else
603-
{
604-
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
605-
}
606-
};
607-
return action().Result;
595+
var policy = RetryConfiguration.AsyncRetryPolicy;
596+
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
597+
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
598+
}
599+
else
600+
{
601+
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
602+
}
608603
};
609604

610-
return Task.FromResult<ApiResponse<T>>(ExecClient(getResponse, setOptions, request, options, configuration));
605+
return ExecClientAsync(getResponse, setOptions, request, options, configuration);
611606
}
612607

613608
#region IAsynchronousClient

samples/client/petstore/csharp/restsharp/net4.7/MultipleFrameworks/src/Org.OpenAPITools/Client/ApiClient.cs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -450,10 +450,9 @@ private ApiResponse<T> ToApiResponse<T>(RestResponse<T> response)
450450
/// <param name="configuration">A per-request configuration object.
451451
/// It is assumed that any merge with GlobalConfiguration has been done before calling this method.</param>
452452
/// <returns>A new ApiResponse instance.</returns>
453-
private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
453+
private async Task<ApiResponse<T>> ExecClientAsync<T>(Func<RestClient, Task<RestResponse<T>>> getResponse, Action<RestClientOptions> setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
454454
{
455455
var baseUrl = configuration.GetOperationServerUrl(options.Operation, options.OperationIndex) ?? _baseUrl;
456-
457456
var clientOptions = new RestClientOptions(baseUrl)
458457
{
459458
ClientCertificates = configuration.ClientCertificates,
@@ -485,7 +484,7 @@ private ApiResponse<T> ExecClient<T>(Func<RestClient, RestResponse<T>> getRespon
485484
{
486485
InterceptRequest(request);
487486

488-
RestResponse<T> response = getResponse(client);
487+
RestResponse<T> response = await getResponse(client);
489488

490489
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
491490
if (typeof(AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
@@ -581,21 +580,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
581580
clientOptions.CookieContainer = cookies;
582581
};
583582

584-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
583+
Func<RestClient, Task<RestResponse<T>>> getResponse = (client) =>
585584
{
586585
if (RetryConfiguration.RetryPolicy != null)
587586
{
588587
var policy = RetryConfiguration.RetryPolicy;
589588
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
590-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
589+
return Task.FromResult(DeserializeRestResponseFromPolicy<T>(client, request, policyResult));
591590
}
592591
else
593592
{
594-
return client.Execute<T>(request);
593+
return Task.FromResult(client.Execute<T>(request));
595594
}
596595
};
597596

598-
return ExecClient(getResponse, setOptions, request, options, configuration);
597+
return ExecClientAsync(getResponse, setOptions, request, options, configuration).GetAwaiter().GetResult();
599598
}
600599

601600
private Task<ApiResponse<T>> ExecAsync<T>(RestRequest request, RequestOptions options, IReadableConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
@@ -605,25 +604,21 @@ private ApiResponse<T> Exec<T>(RestRequest request, RequestOptions options, IRea
605604
//no extra options
606605
};
607606

608-
Func<RestClient, RestResponse<T>> getResponse = (client) =>
607+
Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
609608
{
610-
Func<Task<RestResponse<T>>> action = async () =>
609+
if (RetryConfiguration.AsyncRetryPolicy != null)
611610
{
612-
if (RetryConfiguration.AsyncRetryPolicy != null)
613-
{
614-
var policy = RetryConfiguration.AsyncRetryPolicy;
615-
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
616-
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
617-
}
618-
else
619-
{
620-
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
621-
}
622-
};
623-
return action().Result;
611+
var policy = RetryConfiguration.AsyncRetryPolicy;
612+
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
613+
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
614+
}
615+
else
616+
{
617+
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
618+
}
624619
};
625620

626-
return Task.FromResult<ApiResponse<T>>(ExecClient(getResponse, setOptions, request, options, configuration));
621+
return ExecClientAsync(getResponse, setOptions, request, options, configuration);
627622
}
628623

629624
#region IAsynchronousClient

0 commit comments

Comments
 (0)