简体   繁体   中英

Issue when executing a list of tasks, that have multiple async calls inside each one

I got this tentative piece of code below, that should generate a list of tasks to execute concurrently. The code inside the try...catch... is mean to represent each of those tasks. But the code block itself, contains 3 async calls that should execute sequentially, basically the 2nd call depends on the first and the third on the second.

var syncActions = new List<SyncAction<ContactDto>>();
ContactDto contactDto = null;

var syncActionTasks = updatedNodes.Select(async node =>
{
    SyncAction<IUmbracoActiveCampaignEntity> syncActionResult;
    contactDto = Mapper.Map<ContactDto>(node);

    try
    {
        var firstAsyncCallResult = await this.Contacts
            .GetByEmailAsync<ContactsRoot>(contactDto.Email);

        //...(code omittted for brevity)...

        var secondAsyncCallResult = await this.Contacts
            .AddOrUpdateAsync(firstAsyncCallResult);

        //...(code omittted for brevity)...

        var thirdAsyncCallResult = await this.Contacts
            .GetAccountContactAssociation(secondAsyncCallResult);

    }
    catch (ActiveCampaignException ex)
    {
        // handle error
    }

    return Task.FromResult(contactDto);
})
.ToList();

var result = await Task.WhenAll(syncActionTasks);

//...(code omittted for brevity)...

What I experience, is that the when the code executes the firstAsyncCallResult instead of continuing down to the other 2 async calls, it jumps back to the beginning of the code SyncAction<IUmbracoActiveCampaignEntity> syncActionResult; and although all the code runs "fine" the line var result = await Task.WhenAll(syncActionTasks); returns the right number of contactDto objects, but these objects themselves show up repeated, and not unique as expected.

Any clue, why and what could be adjusted to get the desired outcome? Any directions and suggestions will be greatly appreciated.

What I experience, is that the when the code executes the firstAsyncCallResult instead of continuing down to the other 2 async calls, it jumps back to the beginning of the code SyncAction<IUmbracoActiveCampaignEntity> syncActionResult;

Yes, once the first await is hit, a Task is returned from the lambda and the next iteration will begin. Once the Task returned from GetByEmailAsync has completed, the method will resume.

Also Task.FromResult should not be used in an async method; async methods implicitly return a Task , so you do not need to create one yourself. Simply return the DTO:

return contactDto;

By using Task.FromResult the way you have, the lambda's return type is Task<Task<ContactDto>> .

The call to ToList() is also superfluous, as Task.WhenAll accepts IEnumerable<Task<TResult>> which is already returned from your Select .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM