Отказ от ответственности: Выполнение асинхронного метода внутри синхронного метода часто приводит к тупикам и проблемам с производительностью.Предпочтительным является полностью асинхронный путь вызова или даже полностью синхронный путь.Если вам абсолютно необходимо заблокировать асинхронные методы, читайте дальше.
У меня были подобные случаи, когда запросы HttpClient никогда не возвращались, и ответ обычно был тупиковым.@Eser предоставил ссылку на другой вопрос, который хорошо описывает тупиковый процесс.Подводя итог, вызов GetResult()
заблокировал поток.В то же время PostAsJsonAsync
ожидает разблокировки того же потока, чтобы он мог завершить обработку, создавая тем самым тупик.
Пример асинхронного ожидания / ожидания, который вызывает взаимоблокировку
Одной из возможностей является использование ConfigureAwait(false)
.Это говорит PostAsJsonAsync
, что он может завершить обработку в другом контексте, а не ожидать разблокировки исходного контекста.Тогда функция GetUser()
будет выглядеть следующим образом:
private async Task<User> GetUser()
{
var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new Uri(baseUrl);
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var request = new UserSearchRequest
{
DomainName = "my-corp-domain\my-user-id"
};
var response = await client.PostAsJsonAsync("api/v1/users/search", request).ConfigureAwait(false);
var users = await response.Content.ReadAsAsync<List<User>>().ConfigureAwait(false);
return users.FirstOrDefault();
}
Другое решение, которое я использовал в прошлом, - это обернуть синхронное выполнение внутри Task.Run
.Это помещает начало асинхронного метода в другой контекст, поэтому оба метода не будут пытаться заблокировать один и тот же.Затем метод AuthorizeCore
будет выглядеть следующим образом:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var user = Task.Run(() => GetUser()).GetAwaiter().GetResult();
}
Для получения дополнительной информации об этом методе см. Должен ли я предоставлять синхронные оболочки для асинхронных методов?
Еще раз подчеркиваю, что ни одно из них не является идеальным решением.Выполняя операции «синхронизация по асинхронному», вы теряете все преимущества асинхронной функциональности, одновременно повышая вероятность взаимоблокировок и потенциально худшую производительность.Я рекомендую использовать асинхронный режим до тех пор, пока это возможно.Когда это не так, придерживаться «старых» синхронных методов - не самый плохой вариант.