Introduction
I am developing an ASP.NET application which, among other things, is supposed to retrieve users from Azure Active Directory. For this purpose, I am using the Microsoft Graph version 1.14.0 preview library, which can be found here.
As this library only provides asynchronous methods for retrieving users, I am using the following (pseudo) code to run it synchronously.
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;
Problem
The problem I am facing right now is that upon calling this piece of code from the ASP.NET application, task.IsCompleted
remains forever false
. Now here is the strange part which I can not wrap my head around: the code runs perfectly in both a Console Application and a Unit Test (using NUnit).
One might think that the GraphServiceClient instance is built differently in these versions, but I am 100% positive that it is not. The information that makes it up is loaded from a database, and the code in the Unit Test is exactly the same as the code in the controller of the ASP.NET application. Using the Unit Test, the above code is executed in about 1.5 seconds. In the ASP.NET application, I left it running for as long as 30 minutes without any results, no errors, no time-outs, nothing at all.
I realize this might be a bit of a niche problem, but I do hope that someone has run into the same problem and was able to resolve it.
Update
I managed to resolve this issue. Weirdly enough, converting all my methods to async Tasks did not work, as even await
kept hanging. I do however not fully understand why my solution works now. It looks as though my pseudo-code was not fully accurate, and the solution lies therein.
Attempt #1 (does not work)
This code remains forever in 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());
}
Attempt #2 (does not work)
This method keeps hanging after executing the await
line.
async Task<User> GetUser(string userPrincipalName)
{
User user = await _graphServiceClient.Users[userPrincipalName].Request().GetAsync();
return user;
}
Attempt #3 (works)
This code is basically the same as the code in attempt #1, the only difference being that it does not use the GetResult
method, but it does use the exact same approach as 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;
}
}
While this approach might not be considered best practice, it does work. I am extremely puzzled about why this approach works, because the code in attempt #1 does not, and it is virtually the same code. Can anybody explain why that is?