0
votes

I'm using Microsoft Graph API library (C#) and wondering if anyone has experienced this:
Many of my graph API calls time out from time to time.
This can happen to any API call, from getting current user profile to getting sharepoint documents, and so on. I've tried updating Microsoft Graph API and dependent Nuget packages to the latest versions, but it doesn't help.

To clarify, this application is a Windows console application. On Azure side, it is registered as a native application. As a test application, it is a single-threaded application. No concurrency, race conditions involved. Code logic is as simple as

  1. User logs in.
  2. The program makes a Graph API call (shown in eg.1) to get user's profile and this API call times out.

eg 1.

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

eg 2.

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

The symptom is after a minute or two, it throws an AggregationException(because of TPL) which includes a TimeOutException.
No unauthorized exception.

I want to know what could be the possible cause and how I can avoid that.


UPDATE: Here's a screenshot when the exception happens. enter image description here


UPDATE 2: I've tried replacing all the API calls to use "await" directly to wait for results. because this example code is a console application. I put

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

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

This exception is still thrown from this simple API call:

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

An unhandled exception of type 'Microsoft.Graph.ServiceException' occurred in mscorlib.dll Additional information: Code: timeout

Here's the full call stack

at Microsoft.Graph.HttpProvider.d__19.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.HttpProvider.d__18.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.BaseRequest.d__35.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.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() at SharePointConsoleApp.Program.d__14.MoveNext() in D:\TestProjects\SharePointConsoleApp\Program.cs:line 133 --- 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 Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task) at SharePointConsoleApp.Program.Main(String[] args) in D:\TestProjects\SharePointConsoleApp\Program.cs:line 50 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()

2
What application is using the API? Where are you calling from=>to?tukan
MVC web application. calling the Graph API from server side (C#)detale
Without a minimal reproducible example that clarifies your specific problem or additional details to highlight exactly what was done, it’s hard to reproduce the problem, allowing a better understanding of what is being asked.Nkosi
Possible cause: deadlocks. How to avoid: avoid making blocking calls in async code.Nkosi
More context is needed about where and how the shown code is invoked.Nkosi

2 Answers

0
votes

First of all if it's an application with user interaction you should never do blocking (.Wait() or .Result) calls on the main thread, this will lock-up your application for further user interaction.

So you need to start by using async code, this is a sample of an async Button_Click handler. It will give you a warning, but this seems to be one of the use-cases of an 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;
}

Few days ago I found a nice video about common async/await mistakes

You seem to be talking about a console app running on windows.

As of C# 7.1 you can also have an public static Task Main(string[] args) as starting point. Then your application would look like this:

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

}
0
votes

Maybe the reponse(payload) you get is very huge that while it processes the request times out? I had this issue frequently a while back while I was fiddling with graph api so i used pagination to limit the size/quantity of items sent back by it.