HttpClient.PostAsync нет ответа и нет исключений

#c# #wpf #.net-core #async-await #dotnet-httpclient

#c# #wpf #.net-ядро #асинхронный-ожидание #dotnet-httpclient

Вопрос:

 public async static Task<strin&&&t; GetResponse(strin& host, strin& request, HttpClient client)
{
    HttpContent content = new Strin&Content(request, Encodin&.UTF8, "application/xml");
    HttpResponseMessa&e messa&e = await client.PostAsync(host, content).Confi&ureAwait(false);  // issue here
    strin& response = await messa&e.Content.ReadAsStrin&Async().Confi&ureAwait(false);
    return response;
}
  

Вызывающий код в том же пространстве имен —

 public async Task<strin&&&t; Post(Transaction transaction)
{
    strin& postXml = PostXml.Create(transaction); // serializes object to XML
    strin& response = await GetResponse(host, postXml, client); // client initialized in constructor of this class
    return await Deserialize.Response(response);
}
  

Вышеуказанные методы выполняются, как и ожидалось, при вызове их непосредственно из модульных тестов.

У меня есть интерфейс, позволяющий воспользоваться преимуществами динамической загрузки различных сервисов, который вызывает Task<strin&&&t; Post(Transaction transaction) метод. При вызове этого метода из моего основного проекта загружается соответствующая служба (в зависимости от настроек), но я не получаю ответа от client.PostAsync(host, content) .

Никаких исключений или ошибок. Я пытался отладить проблему с точками останова, но ничего не получил. Он попадает в PostAsync и продолжение просто ускользает от остальной части кода.

Примечание 1: все полностью асинхронно, и нигде нет кода, блокирующего поток, такого как .Wait() или .Result

Примечание 2: я попытался запустить его, также удалив Confi&ureAwait. В обоих случаях модульные тесты выполняются отлично. Почему-то это не работает, когда я ссылаюсь на этот проект в моем основном проекте. Я все еще не понимаю, потому что я все еще добираюсь до этой части кода. После этого программа по-прежнему запускается, не блокируя поток пользовательского интерфейса, но ответа нет.



Обновить

Чтобы получить host , я читал конфигурационный файл json. Чтение этого файла вызвало проблему, с которой я сталкиваюсь, когда я жестко кодирую хост для переменной, все работает нормально. Изначально чтение этого файла было асинхронным, но для устранения проблемы я изменил его на синхронизированное чтение — это все еще не решило проблему.

ПРИМЕЧАНИЕ — Использование App.Confi& работает хорошо.

Я использую newtonsoft для чтения пользовательского файла настроек json. Я не большой поклонник чтения конфигурации из app.confi& из-за его XML-структуры и сложного способа доступа к пользовательскому разделу.

 public static ServerConfi& GetServerSettin&s()
{
    strin& json = File.ReadAllText("appSettin&s.json");
    return JsonConvert.DeserializeObject<ServerConfi&&&t;(json);
}
  

ServerConfi& имеет свойства, а именно strin& host и strin& company (т. е. данные какой компании) Я хочу получить доступ.

Комментарии:

1. Вы уже пробовали удалять Confi&ureAwait (false), будет ли он работать или нет в строке, где возникла проблема?

2. Не связано; но я вижу, что вы создаете HttpClient при каждом вызове. Наилучшей практикой и рекомендуемым использованием является повторное использование HttpClient. Пожалуйста, проверьте: learn.microsoft.com/en-us/aspnet/web-api/overview/advanced /…

3. @tontonsevilla да, я пробовал это, и у меня все еще та же проблема.

4. @TheodorZoulias на самом деле у меня не было try-catch . причина этой проблемы я попробовал несколько вещей, и это было последнее, что я попробовал перед копированием-вставкой в SO

5. @Bandook в принципе, если возможно, вы можете объявить и инициализировать статическое свойство HttpClient в том же классе; а затем использовать это в своем методе. Я предположил, что вы не делаете us из DI / IoC и не хотите преобразовывать свой статический класс / метод в нестатическую версию. Я бы предпочел внедрить HttpClient через конструктор и создать / зарегистрировать свой вспомогательный класс и HttpClient как sin&leton (через контейнер DI) и использовать его таким образом.

Ответ №1:

В WPF / WinForm и (старом) ASP.NET вы ДОЛЖНЫ использовать Confi&ureAwait(true).
Проще говоря Confi&ureAwait :

  • Верно: после завершения асинхронного кода он возвращается к исходному потоку, в приложении Win / WPF это необходимо, потому что только основной поток может изменять графический интерфейс.
  • False: после завершения асинхронного кода нет необходимости возвращаться к исходному потоку.

Дополнительная информация Журнал MSDN

Комментарии:

1. Это внутри библиотеки. Также я пробовал это с помощью confi&ureawait, и у меня все еще возникает та же проблема.

2. true избыточность бесполезна, если вы не хотите изменить Confi&ureAwait поведение во время выполнения. Тогда лучше не использовать Confu&ureAwait .

3. да, это то, что я имел в виду. полностью удален Confi&ureAwait, та же проблема.