I'm not after a solution here, more an explanation of what's going on. I've refactored this code to prevent this problem but I'm intrigued why this call deadlocked. Basically I have a list of head objects and I need to load each ones details from a DB repository object (using Dapper). I attempted to do this using ContinueWith but it failed:
List<headObj> heads = await _repo.GetHeadObjects();
var detailTasks = heads.Select(s => _changeLogRepo.GetDetails(s.Id)
.ContinueWith(c => new ChangeLogViewModel() {
Head = s,
Details = c.Result
}, TaskContinuationOptions.OnlyOnRanToCompletion));
await Task.WhenAll(detailTasks);
//deadlock here
return detailTasks.Select(s => s.Result);
Can someone explain what caused this deadlock? I tried to get my head round what has happened here but I'm not sure. I'm presuming it's something to do with calling .Result in the ContinueWith
Additional information
- This is a webapi app called in an
asynccontext The repo calls are all along the lines of:
public async Task<IEnumerable<ItemChangeLog>> GetDetails(int headId) { using(SqlConnection connection = new SqlConnection(_connectionString)) { return await connection.QueryAsync<ItemChangeLog>(@"SELECT [Id] ,[Description] ,[HeadId] FROM [dbo].[ItemChangeLog] WHERE HeadId = @headId", new { headId }); } }I have since fixed this issue with the following code:
List<headObj> heads = await _repo.GetHeadObjects(); Dictionary<int, Task<IEnumerable<ItemChangeLog>>> tasks = new Dictionary<int, Task<IEnumerable<ItemChangeLog>>>(); //get details for each head and build the vm foreach(ItemChangeHead head in heads) { tasks.Add(head.Id, _changeLogRepo.GetDetails(head.Id)); } await Task.WhenAll(tasks.Values); return heads.Select(s => new ChangeLogViewModel() { Head = s, Details = tasks[s.Id].Result });