John
John

Reputation: 6612

Wait for API calls to finish in button_click method

I have a WPF application which sends data to a web application through POST requests. Currently this is done with PostAsync and that works. However, I see that certain requests finish earlier before another request finishes and that causes errors in the web application.

So I need to wait for until POST request is finished before sending the next request. I know I need to use Task, await and async for this, but I'm struggling in my specific situation.

The code below is the current code, without any async or await, because I'm unsure how to do this due to the chaining of objects.

First I have a button click event which calls an object for exporting the data:

private void exportButton_Click(object sender, RoutedEventArgs e)
{
  var dataExtractor = new DataExtractor();

  // First API call
  dataExtractor.ExportTestSteps(testblockId, testCase);

  // Second API call
  dataExtractor.ExportReportTestSteps(testCase, executionList);
}

These call a method in the DataExtractor class and after getting the right data these methods call the actual sending of the POST request:

public class DataExtractor
{
   public void ExportTestSteps(string testblockId, string testCaseUniqueId)
   {
     ...
     new QualityMonitorApi().StoreReportItem(content);
   }

   public void ExportReportTestSteps(string testCaseUniqueId, ExecutionList executionList)
   {
     ...
     new QualityMonitorApi().StoreReportItem(content);
   }     
}

And the QualityMonitorApi looks like this:

public class QualityMonitorApi
{
  private string baseUrl = "http://localhost:3000/api/v1";
  private static readonly HttpClient Client = new HttpClient();

  public void StoreReportItem(string content)
  {
    string url = baseUrl + "/data_extractor/store_report_item";

    var json = new StringContent(content, Encoding.UTF8, "application/json");
    Client.PostAsync(url, json);
  }
}

Due to the chaining of the classes I'm confused how to make sure API call 2 waits for API call 1 to finish?

Upvotes: 0

Views: 2443

Answers (2)

Emy Ferreira
Emy Ferreira

Reputation: 851

You cannot do that way ? async void is okay, as long as it is an event handler method.

Also, you can store the objects that calls the API (i.e. DataExtractor) to avoid re-instantiating.

private async void exportButton_Click(object sender, RoutedEventArgs e)
{
  var dataExtractor = new DataExtractor();

  // First API call
  await dataExtractor.ExportTestStepsAsync(testblockId, testCase);

  // Second API call
  await dataExtractor.ExportReportTestStepsAsync(testCase, executionList);
}

public class DataExtractor
{
   public async Task ExportTestStepsAsync(string testblockId, string testCaseUniqueId)
   {
     ...
     await new QualityMonitorApi().StoreReportItemAsync(content);
   }

   public async Task ExportReportTestStepsAsync(string testCaseUniqueId, ExecutionList executionList)
   {
     ...
    await new QualityMonitorApi().StoreReportItemAsync(content);
   }     
}

public class QualityMonitorApi
{
  private string baseUrl = "http://localhost:3000/api/v1";
  private static readonly HttpClient Client = new HttpClient();

  public async Task StoreReportItemAsync(string content)
  {
    string url = baseUrl + "/data_extractor/store_report_item";

    var json = new StringContent(content, Encoding.UTF8, "application/json");
    await Client.PostAsync(url, json);
  }
}

See more here about async programmation: https://learn.microsoft.com/en-us/dotnet/csharp/async

Upvotes: 0

Evgeny Gorbovoy
Evgeny Gorbovoy

Reputation: 773

Use async/await

Your async method should look like this:

  public async Task StoreReportItem(string content)
  {
    string url = baseUrl + "/data_extractor/store_report_item";

    var json = new StringContent(content, Encoding.UTF8, "application/json");
    await Client.PostAsync(url, json);
  }

Next use async/await in every method:

   public async Task ExportReportTestSteps(string testCaseUniqueId, ExecutionList executionList)
   {
     ...
     await new QualityMonitorApi().StoreReportItem(content);
   }

and so on..

Upvotes: 1

Related Questions