在MVC应用中使用GraphServiceClient时出现挂起问题求助
在MVC应用中使用GraphServiceClient时出现挂起问题求助
嘿,这个问题我太熟悉了——典型的异步同步混合调用导致的死锁!你遇到的情况刚好是传统ASP.NET MVC里常见的坑,而控制台应用因为没有同步上下文所以不会触发这个问题,咱们一步步来解决:
问题根源分析
在传统ASP.NET(包括MVC)里,每个请求都会关联一个SynchronizationContext。当你在异步方法里用await时,它会捕获这个上下文,等异步操作完成后,后续代码会尝试回到这个上下文继续执行。但如果你在这个上下文里调用.Result或者.Wait()来同步等待异步结果,就会阻塞当前线程,而这个线程刚好持有SynchronizationContext,导致await后续的代码永远无法获取到上下文执行,最终形成死锁。
你的代码里有两处触发死锁的点:
Contact方法里用GetSiteId().Result同步等待异步方法GetSiteId里用credentials.GetTokenAsync(context).Result同步调用异步的Token获取方法
修复方案:全程使用async/await,杜绝同步阻塞
咱们把两处同步调用都改成异步模式,代码就能正常运行了:
修改后的GetSiteId方法
public async Task<string> GetSiteId() { string tenantID = "xxxxxxxx-58a7-4ade-a233-740e8f251911"; string appID = "xxxxxxx-0962-4c42-b14f-00505a836262"; string clientSecret = "xxxxxxxvBcm7ZrKCGevVWOG~ex7blIpfWObTPcJN"; var credentials = new Azure.Identity.ClientSecretCredential(tenantID, appID, clientSecret); var context = new TokenRequestContext(new[] { "https://graph.microsoft.com/.default" }); // 把.Result改成await,异步获取Token var response = await credentials.GetTokenAsync(context); m_graphServiceClient = new GraphServiceClient(credentials); var domain = "xxxxxxxxx.sharepoint.com"; var path = "/sites/root"; var site = await m_graphServiceClient.Sites[$"{domain}:{path}"].GetAsync(); return site.Id; }
修改后的Contact方法
// 把ActionResult改成Task<ActionResult>,方法加上async关键字 public async Task<ActionResult> Contact() { // 用await替代.Result,异步等待GetSiteId完成 ViewBag.Message = await this.GetSiteId(); return View(); }
额外提醒
尽量保持代码的“异步一致性”——要么全程异步,要么全程同步,不要混合使用。尤其是在ASP.NET这类有同步上下文的环境里,同步阻塞异步方法几乎一定会导致死锁问题。
备注:内容来源于stack exchange,提问作者Nicholas Kellner
相关产品推荐
相关产品推荐

