I need to make a a sequence of API calls to an external provider, each call is dependent on the successful response of the previous call. Each calling method is async. The following code is how I approached this task. My concern is that these calls may not be called in sequence, so I am wondering if I am doing the right thing.
var client = await clientRepository.FirstOrDefaultAsync(c => c.UserId == userId).ConfigureAwait(false);
if (client == null)
throw new Exception("Client Not Found");
// Send data to provider
var applicant = await apiClient.CreateApplicantAsync(client).ConfigureAwait(false);
if (applicant == null || applicant.Id.IsNullOrEmpty())
throw new ApiException("Failed to create applicant");
// Send document a to provider
var documentResponse = await apiClient.UploadDocumentAsync(applicant.Id, dto.DocumentA.Stream, dto.DocumentA.FileName, dto.DocumentA.Document.Type).ConfigureAwait(false);
if (documentResponse == null)
throw new ApiException("Failed to upload document");
// Send document b to provider
documentResponse = await apiClient.UploadDocumentAsync(applicant.Id, dto.DocumentB.Stream, dto.DocumentB.FileName, dto.DocumentB.Document.Type).ConfigureAwait(false);
if (documentResponse == null)
throw new ApiException("Failed to upload document");
// Send applicant c to provider
var imageResponse = await apiClient.UploadApplicantImageAsync(applicant.Id, dto.DocumentC.Stream, dto.DocumentC.FileName).ConfigureAwait(false);
if (imageResponse == null)
throw new ApiException("Failed to upload document");
// Check the applicant
var checkResponse = await apiClient.CheckApplicantAsync(applicant.Id).ConfigureAwait(false);
if (checkResponse == null)
throw new ApiException("Applicant check failed");
// Check is successful when the Result property is null
if (checkResponse.Result.IsNullOrEmpty())
{
result.Success();
}
CodePudding user response:
Given your code, there is no way that your API requests wouldn't be called in sequence. Since you await every call directly, this code behaves the same way as if it was synchronous.
I don't know the use case of your application, but if this code is executed in some form of controller you should include a CancellationToken to cancel this long running script in case the user aborts the request.
CodePudding user response:
Given each async Task
is awaited, your code will run synchronously. However, based on the code it seems you could execute the upload tasks concurrently (see example below).
Example showing how you could execute the uploads concurrently:
var client = await clientRepository.FirstOrDefaultAsync(c => c.UserId == userId);
if (client == null)
throw new ApiException("Failed to read client");
// Send data to provider
var applicant = await apiClient.CreateApplicantAsync(client);
if (applicant == null || applicant.Id.IsNullOrEmpty())
throw new ApiException("Failed to create applicant");
// Send files a to provider
var docUploadA = apiClient.UploadDocumentAsync(applicant.Id, dto.DocumentA.Stream, dto.DocumentA.FileName, dto.DocumentA.Document.Type);
var docUploadB = apiClient.UploadDocumentAsync(applicant.Id, dto.DocumentB.Stream, dto.DocumentB.FileName, dto.DocumentB.Document.Type);
var imageUpload = apiClient.UploadApplicantImageAsync(applicant.Id, dto.DocumentC.Stream, dto.DocumentC.FileName);
await Task.WhenAll(docUploadA, docUploadB, imageUpload);
if (docUploadA.Result == null || docUploadB.Result == null || imageUpload.Result == null)
throw new ApiException("Failed to upload document");
// Check the applicant
var checkResponse = await apiClient.CheckApplicantAsync(applicant.Id);
if (checkResponse == null)
throw new ApiException("Applicant check failed");
// Check is successful when the Result property is null
if (checkResponse.Result.IsNullOrEmpty())
{
result.Success();
}