如何在lambda函数中使用async/await

3

如何在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控制器内运行,它没有任何错误,问题是它需要一个额外的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);

1
这可能永远不会返回,因为你在某个地方同步等待。经典的 ASP.NET 死锁。也许是在用户管理器中? - usr
@usr 我不这么认为,_usermanager 是继承自AspNet.Identity的UserManager - dafriskymonkey
“它需要在某个地方添加额外的await” - 这是什么意思?为什么添加一个await会改善情况?至于“永远不返回”,如果调用者正在等待,那么方法中唯一可能导致其卡住的两个地方是对ToListAsync()Ok()的调用。你的第一步是在调试器中观察执行过程,看看是哪个地方出了问题,然后跟踪代码到达该点的确切位置(即实际上没有返回的调用正在等待什么)。 - Peter Duniho
好的,那可能是正确的。你怎么知道这个操作从不返回?当你暂停调试器时,是否有一个线程在某个有意义的调用堆栈处等待?当你使用调试器单步执行时,它在哪里挂起? - usr
@usr 我曾试图使用 AJAX 调用和 Fiddler,但两者都没有响应。 - dafriskymonkey
@dafriskymonkey,你写的那个答案应该被添加到你的问题下面,并标记为正确答案。下面那一个回答“看起来”像是唯一发布并且有赞同的答案,但实际上它并没有解决你的问题或者满足你的需求。 - pbristow
1个回答

12

思考一下你的类型。

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")
});

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

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

1
内部服务器错误 :)在上一个异步操作完成之前,此上下文上已启动第二个操作。请使用“await”确保任何异步操作在调用此上下文上的另一个方法之前已完成。任何实例成员都不能保证是线程安全的。 - dafriskymonkey
1
我仍然认为我们需要在某个地方添加额外的await - dafriskymonkey
@dafriskymonkey:很可能是其他代码引起了异常。请发布一个最小化的、可重现的示例。 - Stephen Cleary
@StephenCleary 这是最小可重现的示例。内部异常显示:“连接不支持 MultipleActiveResultSets”!!! - dafriskymonkey
4
那么这就是你的答案,你不能并行执行此任务,因为你正在访问的底层数据要求你一次只能执行一个查询。 - Ana Betts
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接