【问题标题】:Why would an EF query with ToListAsync hang in a WPF application?为什么带有 ToListAsync 的 EF 查询会在 WPF 应用程序中挂起?
【发布时间】:2017-06-17 20:03:29
【问题描述】:

这是查询:

using (var db = new AppDbContext())
{
    var items = await db.Branches
        .Where(b => b.OrgId == orgId)
        .Select(t => new SelectListItem<int> {Key = t.Id, Value = t.Name})
        .ToListAsync();
    return items;
}

如果我用ToList 替换ToListAsync,它运行良好,但否则它会挂起。我怀疑某种线程问题。该查询是在我的视图模型的 InitializeAsync 方法期间调用的,该方法是从视图中的“事件”调用的:

public override async void OnNavigatedTo(NavigationContext navigationContext)
{
    await InitializeModelAsync(InitModelCts.Token);
}

这是INavigationAware 的视图实现的一部分。

【问题讨论】:

  • 这可能会有所帮助:ToListAsync() does not complete at all
  • 在这两种情况下检查 ThreadId。如果它们不同,则使用调度程序代替
  • 这可能是因为OnNavigatedTo 从一开始就不是真正的async 吗?我找到了this blog

标签: c# wpf async-await prism


【解决方案1】:

如果不通过调用ConfigureAwait 方法捕获上下文是否有效?:

using (var db = new AppDbContext())
{
    var items = await db.Branches
        .Where(b => b.OrgId == orgId)
        .Select(t => new SelectListItem<int> { Key = t.Id, Value = t.Name })
        .ToListAsync().ConfigureAwait(false);
    return items;
}

还要注意初始实体框架设置并不是真正异步的:

EF6 ToListAsync freezes Winforms

...所以您可能希望将整个查询和上下文创建卸载到后台线程:

await Task.Run(()=> 
{
    using (var db = new AppDbContext())
    {
        var items = db.Branches
                    .Where(b => b.OrgId == orgId)
                    .Select(t => new SelectListItem<int> { Key = t.Id, Value = t.Name })
                    .ToList();
        return items;
    }
});

【讨论】:

  • 我使用SynchronizationContext.Post 解决了这个问题,并使用了一个等待查询的委托,就像ToListAsync 一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2014-04-27
  • 1970-01-01
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2015-03-02
相关资源
最近更新 更多