You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 15:48:04