Как правильно использовать HttpClient синхронно? - PullRequest
0 голосов
/ 29 ноября 2018

Я использовал кавычки вокруг «правильного пути», потому что я уже хорошо знаю, что правильный способ использования асинхронного API - просто позволить асинхронному поведению распространяться по всей цепочке вызовов.Это не вариант здесь.

Я имею дело с очень большой и сложной системой, специально разработанной для синхронной пакетной обработки в цикле.

Причина, по которой я неожиданно использую HttpClient, заключается в том, чтопотому что до этого все данные для пакетной обработки собирались из базы данных SQL, и теперь мы добавляем вызов Web API в смесь.

Да, мы вызываем Web API в синхронном исполнениипетля.Я знаю.Переписать все, чтобы быть асинхронным, просто не вариант.Это на самом деле то, что мы хотим сделать.(Мы максимально сокращаем количество вызовов API)

Я на самом деле сделал попытался распространить асинхронное поведение вверх по цепочке вызовов, но затем я обнаружил, что в 50 файлахизменения, все еще с сотнями ошибок компилятора, чтобы решить, и потерял всякую надежду.Я потерпел поражение.

Итак, вернемся к вопросу, учитывая рекомендацию Microsoft никогда не использовать WebRequest для новых разработок и вместо этого использовать HttpClient, который предлагает только асинхронный API, что мне делать?

Вот некоторый псевдокод того, что я делаю ...

foreach (var thingToProcess in thingsToProcess)
{
    thingToProcess.ProcessStuff(); // This makes an API call
}

Как мне реализовать ProcessStuff ()?

Моя первая реализация выглядела так

public void ProcessStuff()
{
    var apiResponse = myHttpClient // this is an instance of HttpClient
        .GetAsync(someUrl)
        .Result;

    // do some stuff with the apiResponse
}

Однако мне сказали, что вызов .Result таким образом может привести к тупикам, когда он вызывается из чего-то вроде ASP.NET из-за контекста синхронизации.

Угадайте, что этот пакетный процесс будетбыть сброшенным с контроллера ASP.NET.Да, опять же, я знаю, это глупо.Когда он запускается из ASP.NET, он «пакетно обрабатывает» только один элемент, а не весь пакет, но я отступаю, он по-прежнему вызывается из ASP.NET, и поэтому я беспокоюсь о взаимоблокировках.

«правильный способ» справиться с этим?

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Вы также можете посмотреть на использование Nito.AsyncEx, который представляет собой пакет nuget.Я слышал о проблемах с использованием Task.Run (), и это это устраняет это.Вот ссылка на документы API: http://dotnetapis.com/pkg/Nito.AsyncEx/4.0.1/net45/doc/Nito.AsyncEx.AsyncContext

А вот пример использования асинхронного метода в консольном приложении: https://blog.stephencleary.com/2012/02/async-console-programs.html

0 голосов
/ 29 ноября 2018

Попробуйте выполнить следующие действия:

var task = Task.Run(() => myHttpClient.GetAsync(someUrl)); 
task.Wait();
var response = task.Result;

Используйте его только тогда, когда вы не можете использовать асинхронный метод.

Этот метод абсолютно свободен от взаимоблокировок, как упомянуто в блоге msdn- https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-in-main-context/

...