Joh*_*ens 7 c# active-directory azure microsoft-graph-api
我正在开发一个 ASP.NET 应用程序,除其他外,它应该从 Azure Active Directory 检索用户。为此,我使用了 Microsoft Graph 1.14.0 版预览库,可在此处找到。
由于该库仅提供用于检索用户的异步方法,因此我使用以下(伪)代码来同步运行它。
string userPrincipalName = "test.user@intuneforeducation.com";
var task = Task.Run(async () => await _graphServiceClient.Users[userPrincipalName].Request().GetAsync());
while (!task.IsCompleted)
Thread.Sleep(200);
User retrievedUser = task.Result;
Run Code Online (Sandbox Code Playgroud)
我现在面临的问题是,在从 ASP.NET 应用程序调用这段代码时,task.IsCompleted永远保持false. 现在这是我无法理解的奇怪部分:代码在控制台应用程序和单元测试(使用 NUnit)中完美运行。
有人可能认为 GraphServiceClient 实例在这些版本中的构建方式不同,但我 100% 肯定它不是。组成它的信息是从数据库中加载的,单元测试中的代码与 ASP.NET 应用程序的控制器中的代码完全相同。使用单元测试,上述代码在大约 1.5 秒内执行完毕。在 ASP.NET 应用程序中,我让它运行了长达 30 分钟,没有任何结果,没有错误,没有超时,什么也没有。
我意识到这可能是一个小众问题,但我确实希望有人遇到同样的问题并能够解决它。
我设法解决了这个问题。奇怪的是,将我所有的方法转换为异步任务并没有奏效,甚至await一直挂着。然而,我不完全理解为什么我的解决方案现在有效。看起来我的伪代码并不完全准确,解决方案就在其中。
此代码永远保留在while (!runTask.IsCompleted).
object GetResult<TResult>(Task<TResult> task)
{
using (task)
using (var runTask = Task.Run(async () => await task))
{
while (!runTask.IsCompleted)
Thread.Sleep(SleepTime);
if (runTask.Exception != null)
throw runTask.Exception.InnerException ?? runTask.Exception;
return runTask.Result;
}
}
User GetUser(string userPrincipalName)
{
return (User)GetResult(_graphServiceClient.Users[userPrincipalName].Request().GetAsync());
}
Run Code Online (Sandbox Code Playgroud)
此方法在执行该await行后一直挂起。
async Task<User> GetUser(string userPrincipalName)
{
User user = await _graphServiceClient.Users[userPrincipalName].Request().GetAsync();
return user;
}
Run Code Online (Sandbox Code Playgroud)
此代码与尝试 #1 中的代码基本相同,唯一的区别是它不使用该GetResult方法,但它确实使用了与GetResult.
User GetUser(string userPrincipalName)
{
using(var task = Task.Run(async () => await _graphServiceClient.Users[userPrincipalName].Request().GetAsync()))
{
while (!task.IsCompleted)
Thread.Sleep(200);
return task.Result;
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这种方法可能不被视为最佳实践,但它确实有效。我对为什么这种方法有效感到非常困惑,因为尝试 #1 中的代码没有,而且它实际上是相同的代码。任何人都可以解释为什么会这样吗?
Gab*_*uci -2
简短的答案是制定你的方法async并执行以下操作:
string userPrincipalName = "test.user@intuneforeducation.com";
User retrievedUser = await _graphServiceClient.Users[userPrincipalName].Request().GetAsync();
Run Code Online (Sandbox Code Playgroud)
任何时候使用.Result(通常称为“同步优于异步”),如果不非常小心,就会面临死锁的风险。死锁意味着两个任务正在等待对方完成,这意味着什么也没有发生。
特别是在 ASP.NET 中,最好始终使用async/ await:在此方法中使用它,一直到控制器。它是:
如果您想深入了解并确切了解死锁发生的原因,Stephen Cleary 有一篇很棒的文章:Don't Block on Async Code
| 归档时间: |
|
| 查看次数: |
2577 次 |
| 最近记录: |