Введение
Я занимаюсь разработкой приложения ASP.NET, которое, помимо прочего, должно извлекать пользователей из Azure Active Directory. Для этой цели я использую библиотеку предварительного просмотра Microsoft Graph версии 1.14.0, которую можно найти здесь .
Поскольку эта библиотека предоставляет только асинхронные методы для извлечения пользователей, я использую следующий (псевдо) код для синхронного запуска.
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;
Задача
Проблема, с которой я сейчас сталкиваюсь, заключается в том, что при вызове этого фрагмента кода из приложения ASP.NET task.IsCompleted
остается навсегда false
. Теперь вот странная часть, которую я не могу обернуть: код отлично работает как в консольном приложении, так и в модульном тесте (с использованием NUnit).
Можно подумать, что экземпляр GraphServiceClient в этих версиях построен по-другому, но я на 100% уверен, что это не так. Информация, из которой он состоит, загружается из базы данных, и код в модульном тесте точно такой же, как код в контроллере приложения ASP.NET. Используя модульный тест, приведенный выше код выполняется примерно за 1,5 секунды. В приложении ASP.NET я оставлял его запущенным в течение 30 минут без каких-либо результатов, без ошибок, без тайм-аутов, вообще ничего.
Я понимаю, что это может быть проблемой ниши, но я надеюсь, что кто-то столкнулся с той же проблемой и смог ее решить.
Обновление
Мне удалось решить эту проблему. Как ни странно, преобразование всех моих методов в асинхронные задачи не сработало, так как даже await
продолжал зависать. Однако я не совсем понимаю, почему мое решение работает сейчас. Похоже, что мой псевдокод не был полностью точным, и решение лежит в этом.
Попытка # 1 (не работает)
Этот код остается навсегда в 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());
}
Попытка # 2 (не работает)
Этот метод продолжает зависать после выполнения строки await
.
async Task<User> GetUser(string userPrincipalName)
{
User user = await _graphServiceClient.Users[userPrincipalName].Request().GetAsync();
return user;
}
Попытка № 3 (работает)
Этот код в основном совпадает с кодом в попытке № 1, с той лишь разницей, что он не использует метод GetResult
, но он использует тот же подход, что и 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;
}
}
Хотя этот подход не может считаться лучшей практикой, он работает. Я чрезвычайно озадачен тем, почему этот подход работает, потому что код в попытке № 1 нет, и это практически тот же код. Кто-нибудь может объяснить, почему это так?