GetRolesAsync 无痕迹地退出

Posted

技术标签:

【中文标题】GetRolesAsync 无痕迹地退出【英文标题】:GetRolesAsync exits without a trace 【发布时间】:2021-03-18 23:34:48 【问题描述】:

这是一个 Blazor 服务器应用程序。我使用 Serilog,但没有显示任何信息。我希望某处会出现异常,但代码只是存在而没有踪迹。

这是我正在尝试做的简化版本。它在两个 GetRolesAsync 中的任何一个处随机退出:

// Both injected as Scoped at Startup.cs
private UserManager<IdentityUser> _userManager;
private RoleManager<IdentityRole> _roleManager;

public Task<IdentityUser> FetchIdentityUser()

    // Two users:
    var allUsers = _userManager.Users.ToList();
    
    // Two roles:
    var allRoles = _roleManager.Roles.ToList();
    
    // Each user is attached to a single role in the db
    // (checked via mysqlWorkbench)

    var roleNames1 = _userManager.GetRolesAsync(allUsers.First()).Result; // <-- sometimes it exits here (no exception is thrown, no trace of what's going on ...)
    var roleNames2 = _userManager.GetRolesAsync(allUsers.Last()).Result; // <-- ...and sometimes it exists here (no exception is thrown, no trace of what's goin on ...)
    
    return Task.FromResult(allUsers.First());

【问题讨论】:

不应该 FetchIdentityUser() 是异步的,然后你会 await 那两个 GetRolesAsync 调用?不确定,但这会出现在这里更有意义。 任何时候你发现自己在输入.Result,你可能做错了非常非常错误(需要注意的是,对已经完成的任务进行微优化离开状态机; 如果你不知道确切这意味着什么:不要使用.Result) - 你应该使用var roleName1 = await _userManager.GetRolesAsync(allUsers.First());roleNames2类似) - 并将方法标记为@987654328 @ @MarcGravell 你是对的。通常我选择.Result 是因为“异步蠕变”(如果您不小心,它会迅速在您的代码中传播,最终导致一团糟)。例如:我已经以某种方式设计了一个代码,并且在我的代码中一直有一个等待的函数......感谢您的反馈(以及创建 Dapper!;)这使得 db 访问变得更简单和直观) . 【参考方案1】:

这些是异步方法,您需要等待它们。

编辑(感谢 Mark Gravell 的评论):您可能在这里看到的是同步上下文死锁,因为它们试图返回调用线程。这也可以更好地解释为什么您很难看到错误!

public **async** Task<IdentityUser> FetchIdentityUser()

    // Two users:
    var allUsers = _userManager.Users.ToList();
    
    // Two roles:
    var allRoles = _roleManager.Roles.ToList();
    
    // Each user is attached to a single role in the db
    // (checked via MysqlWorkbench)

    var roleNames1 = await _userManager.GetRolesAsync(allUsers.First()); // <-- sometimes it exits here (no exception is thrown, no trace of what's going on ...)
    var roleNames2 = await _userManager.GetRolesAsync(allUsers.Last()); // <-- ...and sometimes it exists here (no exception is thrown, no trace of what's goin on ...)
    
    return Task.FromResult(allUsers.First());

您需要等待并将方法本身标记为异步(确保在调用它的地方等待它)。

在极少数情况下,您应该直接访问此类任务的结果,并且您需要明确结构化的代码才能使其工作。

【讨论】:

因为UserManager&lt;TUser&gt;.GetRolsAsync(TUser) returns a task,这里不应该有竞争条件——它应该变成阻塞;它更有可能是由该阻塞引起的同步上下文死锁(请注意,您所描述的情况可能发生在涉及ValueTask&lt;T&gt; 的某些场景中,特别是在使用IValueTaskSource&lt;T&gt; 时)。不过,修复仍然是使用await,所以:太好了! 是的,这确实解决了这个问题。问题是我帖子中的代码过于简化(尽管问题是相同的)。在我的原始代码中,我正在这样做:allUsers.Select(u =&gt; var roleNames = _userManager.GetRolesAsync(u).Result; ... ,我没有使用await,因为我不知道我可以这样做:allUsers.Select(async u =&gt; var roleNames = await _userManager.GetRolesAsync(u); ... ,这解决了这个问题。这是我第一次使用 Identity,但由于“幕后”发生的所有事情,我发现它很难使用。

以上是关于GetRolesAsync 无痕迹地退出的主要内容,如果未能解决你的问题,请参考以下文章

Linux之系统痕迹命令

pyqt5异常退出无提示信息

节点无错误退出且不等待承诺(事件回调)

页面无任何操作30秒后退出1

用户停留网站无操作,一定时间后自动退出

删除临时文件时 C# 应用程序无异常退出