【问题标题】:Microsoft Graph API timeout exceptionMicrosoft Graph API 超时异常
【发布时间】:2019-06-05 18:10:31
【问题描述】:

我正在使用 Microsoft Graph API 库 (C#),想知道是否有人遇到过这种情况:
我的许多图形 API 调用有时会超时。
这可能发生在任何 API 调用中,从获取当前用户配置文件到获取共享点文档等等。 我已尝试将 Microsoft Graph API 和依赖的 Nuget 包更新到最新版本,但没有帮助。

为了澄清,这个应用程序是一个 Windows 控制台应用程序。在 Azure 端,它被注册为本机应用程序。作为一个测试应用程序,它是一个单线程应用程序。不涉及并发,竞争条件。代码逻辑就这么简单

  1. 用户登录。
  2. 程序调用 Graph API(如示例 1 所示)以获取用户的个人资料,但此 API 调用超时。

例如 1.

var currentUser = graphClient.Me.Request().GetAsync().Result;

例如 2.

var site = _graphClient.Sites[SharePointSiteId].Request().GetAsync().Result;

症状是在一两分钟后,它抛出一个 AggregationException(因为 TPL),其中包括一个 TimeOutException。
没有未经授权的例外。

我想知道可能的原因以及如何避免这种情况。


更新: 这是发生异常时的屏幕截图。


更新 2: 我尝试替换所有 API 调用以直接使用“await”来等待结果。因为这个示例代码是一个控制台应用程序。我把

static void Main(string[] args)
{
    // using Stephen Cleary's nuget package: Nito.AsyncEx.Tasks
    MainImp().WaitAndUnwrapException();
}

static async Task MainImp()
{
    // ...
    // Graph API calls

这个简单的 API 调用仍然会抛出这个异常:

var currentUser = await graphClient.Me.Request().GetAsync();

在 mscorlib.dll 中出现“Microsoft.Graph.ServiceException”类型的未处理异常 附加信息:代码:超时

这是完整的调用堆栈

在 Microsoft.Graph.HttpProvider.d__19.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.Graph.HttpProvider.d__18.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.Graph.BaseRequest.d__35.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.Graph.BaseRequest.d__311.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Graph.UserRequest.<GetAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在 SharePointConsoleApp.Program.d__14.MoveNext() 中 D:\TestProjects\SharePointConsoleApp\Program.cs:第 133 行 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(任务 任务)在 SharePointConsoleApp.Program.Main(String[] args) 中 D:\TestProjects\SharePointConsoleApp\Program.cs:第 50 行 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] args) 在 System.AppDomain.ExecuteAssembly(String assemblyFile, 证据 assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态)
在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback 回调、对象状态)在 System.Threading.ThreadHelper.ThreadStart()

【问题讨论】:

  • 什么应用程序正在使用 API?你从哪里打电话=>到哪里?
  • MVC 网络应用程序。从服务器端调用 Graph API (C#)
  • 如果没有 minimal reproducible example 澄清您的具体问题或其他详细信息以准确突出所做的工作,就很难重现问题,从而更好地理解所询问的内容。
  • 可能原因:死锁。如何避免:避免在异步代码中进行阻塞调用。
  • 需要更多关于在何处以及如何调用所示代码的上下文。

标签: c# sharepoint microsoft-graph-api sharepoint-online


【解决方案1】:

首先,如果它是一个与用户交互的应用程序,你不应该在主线程上进行阻塞(.Wait().Result)调用,这将锁定你的应用程序以进行进一步的用户交互。

所以您需要从使用异步代码开始,这是一个异步 Button_Click 处理程序的示例。它会给你一个警告,但这似乎是 async void 的用例之一。

private async void Button_Click(object sender, RoutedEventArgs 
{
    var currentUser = await graphClient.Me.Request().GetAsync();
    // Presumably do something with the response
    labelUser.Text = currentUser.DisplayName;
}

几天前我发现了一个关于常见异步/等待错误的nice video

您似乎在谈论在 Windows 上运行的控制台应用程序。

从 C# 7.1 开始,您还可以将 public static Task Main(string[] args) 作为起点。那么您的应用程序将如下所示:

public static async Task Main(string[] args) {
  // Create the client here.....
  var graphClient = .....;
  // Await every call to the graphclient
  var currentUser = await graphClient.Me.Request().GetAsync();
  // Do something with the user

}

【讨论】:

  • 我的工作环境没有安装 C# 7.1,但除此之外,我将所有其他具有异步方法的代码一直更新到 Main 方法,但它仍然可能超时。不过谢谢!
  • 如果您的程序在请求完成之前结束,它也会超时。您是否有更完整的超时代码示例?
【解决方案2】:

也许您得到的响应(有效负载)非常大,以至于在处理请求时超时?前段时间我在摆弄图形 api 时经常遇到这个问题,所以我使用 pagination 来限制它发回的项目的大小/数量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 2020-05-07
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    相关资源
    最近更新 更多