2

I'm new to C#. I want to start 4 PostAsync without wait for response, and then check if any of them is completed and HTTP response contain a specific word then cancel other async tasks.

And if a completed PostAsync does not contain the word or is failed, run another task so that total of all async tasks stay at 4

private async void Button_Click(object sender, RoutedEventArgs e)
{
    List<Task> tasks = new List<Task>();
    for (int ctr = 0; ctr <= 2; ctr++)
    {
        tasks.Add(Web("https://google.com/api/", da));
    }
    
    var index = Task.WhenAny(tasks).Result;
}

public static async Task<string> Web(string url, string da)
{
     var response = await client.PostAsync(url,
         new StringContent(da, Encoding.UTF8, "application/json"));

     return response.Content.ReadAsStringAsync().Result; ;
}

I tested above code but don't know how to get the result of completed task, nor add another task in case of failure.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Hamid Z
  • 180
  • 1
  • 14
  • 2
    The `WhenAny()` method returns the task object that completed. Instead of using `Result`, which is wrong because it blocks, negating the whole benefit of using `WhenAny()`, write `var task = await Task.WhenAny(tasks)` and the `task` variable will contain the `Task` object that completed. As far as cancelling the remaining ones goes, just make sure the tasks are cancellable (i.e. you've passed a cancel token to each), and trigger the cancel token, i.e. by cancelling the cancellation token source where you got the token in the first place. See duplicate. – Peter Duniho Jun 26 '21 at 17:16
  • 1
    I'll note that the variable name `index` is misleading, because the value returned by `Task.WhenAny()` is not an index, but rather a task. You seem to have confused `WhenAny()` with `WaitAny()`. – Peter Duniho Jun 26 '21 at 17:17
  • Please check out these questions: [Async HTTP requests inside for loop without await](https://stackoverflow.com/questions/68028107/async-http-requests-inside-for-loop-without-await) and [Task.WhenAny with cancellation of the non completed tasks and timeout](https://stackoverflow.com/questions/56207326/task-whenany-with-cancellation-of-the-non-completed-tasks-and-timeout). The first is probably exactly what you want. – Theodor Zoulias Jun 27 '21 at 05:01
  • Screenshot: [PostAsync debug] Answered on another issue: https://stackoverflow.com/a/69781897/11750551 – smirad91 Oct 30 '21 at 20:30

1 Answers1

1

WhenAny will return the first completed task. not an integer. for getting the result you can await the same.

   var completedTask = Task.WhenAny(tasks);

   var result =await completedTask;

do not use task.result ever as it will block the executions.

WhenAny provides an option to asyncrnously iterate through the list of tasks. you can add /remove the tasks to list directly inside the iteration loop. (for cancellation need to pass the same cancellation token for all tasks)

  • for more info on whenany - please check https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/start-multiple-async-tasks-and-process-them-as-they-complete – priyasukumar Jun 27 '21 at 11:07