Home > Back-end >  Why Task.WhenAll return null?
Why Task.WhenAll return null?

Time:10-13

I have two methods which return independent data. I assume it's a good idea to run them in parallel. Without any modifications code look's like:

private async Task<Entity> MethodAsync()
{
    ...
    var model1 = await client.Method1(Id1, cancellationToken);            
    var model2 = await client.Method2(Id2, cancellationToken);
    ...
}

Those methods return data as I expecting. Now when I change code all methods return "null". When I inspect Task object in visual studio there are properties Id = 2356, Status = RanToCompletion, Method = "{null}", Result = "".

private async Task<Entity> MethodAsync()
{
     var model1Task = client.Method1(Id1, cancellationToken);
     var model2Task = client.Method2(Id2, cancellationToken);
     var task = Task.WhenAll(new Task[] { model1Task ,model2Task });         
     await task;     //doesn't work
     //task.Wait();  //doesn't work
     //await Task.WhenAll(new Task[] { model1Task , model2Task }); //doesn't work
     //Task.WhenAll(new Task[] { model1Task, model2Task}); //doesn't work
}

Code of client methods almost the same:

public async Task<Model> Method1(Guid Id, CancellationToken cancellationToken)
{
    HttpResponseMessage responseMessage = await client.GetAsync($"customEndPoint");
    ResponseMessageSingle<Model> response = JsonSerializer.Deserialize<ResponseMessageSingle<Model>>(
        await responseMessage.Content.ReadAsStringAsync(cancellationToken),
        new JsonSerializerOptions(JsonSerializerDefaults.Web));

    return response.result;
}       

private class ResponseMessageSingle<T>
{
    public bool success { get; set; }
    public string message { get; set; }
    public T result { get; set; }
}

Also there is AuthorizeInterceptor(DelegatingHandler):

protected override async Task<HttpResponseMessage> SendAsync(
          HttpRequestMessage request, CancellationToken cancellationToken)
 {
      some logic...
      request.SetBearerToken(TokenResponse.AccessToken);
      HttpResponseMessage response = await base.SendAsync(request, cancellationToken);    
      return await Task.FromResult(response);
 }

CodePudding user response:

Task.WhenAll does not return a result in your case, because you create an array of Task, which has no result. And since your tasks return different results, you cannot get that in an array nicely.

You should change your code like this to get the results of your methods:

private async Task<Entity> MethodAsync()
{
    var model1Task = client.Method1(Id1, cancellationToken);
    var model2Task = client.Method2(Id2, cancellationToken);
    var task = Task.WhenAll(new Task[] { model1Task ,model2Task });         
    await task;
    var result1 = await model1Task;
    var result2 = await model2Task;
    ...
 }

Since both methods will be completed, awaiting them will just immediately get you the results.

CodePudding user response:

There is no need for Task.WhenAll here, because:

var model1Task = client.Method1(Id1, cancellationToken);
var model2Task = client.Method2(Id2, cancellationToken);

will call each Method1 and Method2 and thus start their respective async operations. Note that nothing is being awaited here, yet.

With the async operations of both Method1 and Method2 now executing, you can proceed with just awaiting each task individually:

var model1 = await model1Task;
var model2 = await model2Task;

These two assignments will finish execution once both model1Task and model2Task have been completed in whatever order. Which pretty much seems what you are shooting for here, and therefore Task.WhenAll is not of much use in your case. And which in the end means: If there is no Task.WhenAll anymore, any problem/error you faced related to Task.WhenAll is not anymore, either.

  •  Tags:  
  • c#
  • Related