【问题标题】:how to use async/await inside a lambda如何在 lambda 中使用 async/await
【发布时间】:2014-11-29 16:16:39
【问题描述】:

如何在 lambda 表达式中正确使用 async/await 关键字?这是代码:

public async Task<IHttpActionResult> GetUsers() {

        var query = await _db.Users.ToListAsync();

        var users = query.Select(async u =>  new
        {
            FirstName = u.FirstName,
            LastName = u.LastName,
            IsGeek = await _userManager.IsInRoleAsync(u.Id, "Geek")
        });

        return Ok(users);
}

正如你所看到的,这段代码在 webapi 控制器中运行,它编译没有任何错误,问题是它需要一个 extra await 某处,因为这个动作永远不会重新运行。

注意_db_usermanager 是应用程序的DbContextUserManager

谢谢。

更新

这个等效的代码永远不会失败(但它并不优雅:():

var query = await _db.Users.ToListAsync();
var users = new List<object>();
foreach (var u in query)
{
     bool IsGeek = await _userManager.IsInRoleAsync(u.Id, "IsGeek");
     users.Add( new {
         FirstName = u.FirstName,
         LastName = u.LastName,
         IsGeek= IsGeek
      });
 }
return Ok(users);

【问题讨论】:

  • 这可能永远不会返回,因为您正在某个地方同步等待。经典的 ASP.NET 死锁。也许在用户管理器中?
  • @usr 我不这么认为,_usermanager 继承自 AspNet.Identity UserManager
  • “它需要在某个地方额外等待”——你的意思是什么?为什么添加await 会改善情况?至于“永不返回”,不清楚你是如何称呼它的,但如果调用者是awaiting,那么方法中唯一可以设置卡住的两个地方是对ToListAsync()的调用和调用到Ok()。您的第一步是在调试器中观察执行情况并查看执行情况,然后准确追踪代码在该点的位置(即实际等待未返回的调用是什么)。
  • 好的,那可能是正确的。你怎么知道这个动作永远不会返回?当您暂停调试器时,是否有线程在某个有意义的调用堆栈中等待?当您单步调试调试器时,它会挂在哪里?
  • @usr 我正在尝试使用 ajax 调用和提琴手,都没有回来。

标签: c# linq lambda async-await asp.net-web-api


【解决方案1】:

想想你的类型。

var query = await _db.Users.ToListAsync();

query 是用户列表。

var users = query.Select(async u =>  new
{
    FirstName = u.FirstName,
    LastName = u.LastName,
    IsGeek = await _userManager.IsInRoleAsync(u.Id, "Geek")
});

当您 Select 使用 async lambda 时,结果是一个任务序列。因此,要(异步)等待所有这些任务完成,请使用Task.WhenAll

var result = await Task.WhenAll(users);
return Ok(result);

【讨论】:

  • 但是为什么请求会挂起?
  • Internal server error :) "在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用 'await' 确保在此上下文上调用另一个方法之前已完成任何异步操作。任何实例成员不能保证是线程安全的。”
  • 我仍然认为我们需要一个额外的await 在某个地方。
  • @dafriskymonkey:其他代码可能会导致该异常。请发布一个最小的、可重现的示例。
  • 那是你的答案,你不能并行化这个任务,因为你正在访问的底层数据要求你一次只做一个查询
猜你喜欢
  • 2017-01-23
  • 2022-01-27
  • 2019-11-27
  • 2019-07-20
  • 2021-10-10
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多