2015-05-27 7 views
4

Недавно я столкнулся с проблемами производительности при использовании HttpClients.PostAsync на .Net 4.5.1. Первоначально сервер (Owin + WebApi) представлял буферную реакцию перед отправкой. Это вызвало огромные издержки использования памяти (размер сериализованного ответа составляет> 1 Гбит). После того, как я включил поток ответов на сервере, клиент буквально прекратил работать. Оказалось, что причиной было перераспределение буфера на клиенте при чтении ответа с сервера. Я проверил HttpClient реализации и нашел интересную часть в HttpClient.SendAsync методе:Зачем нужен буфер HttpClient.PostAsync?

if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead) 
{ 
    this.SetTaskCompleted(request, linkedCts, tcs, result); 
} 
else 
{ 
    this.StartContentBuffering(request, linkedCts, tcs, result); 
} 

Так что, когда completionOption не ResponseHeadersRead ответа всегда буферизации. Согласно SendAsync documentation реализация SendAsync согласуется с намерением.

Теперь, когда PostAsync реализована отправка ResponseContentRead, поток ответа всегда буферизуется POST. Поэтому вопрос в том, почему PostAsync должен ждать (и буфер) для полного ответа, чтобы прибыть до продолжения обработки?

ответ

7

Есть очевидная часть - если вы не укажете HttpCompletionOption.ResponseHeadersRead, то Task будет заполнен только тогда, когда будет прочитан весь отклик; вы должны сохранить данные ответа где-то тем временем.

Почему PostAsync не позволяет указать HttpCompletionOption.ResponseHeadersRead? Наверное, потому что на самом деле это не все, что полезно, большую часть времени. POST предназначен для размещения данных, а не для их получения - это GET. HttpClient был разработан для служб WebAPI и «REST», при правильном использовании HTTP-глаголов.

Если вам нужно использовать POST для получения таких больших объемов данных, у вас есть два основных варианта:

  • Используйте SendAsync
  • Не используйте HttpClient (HttpWebRequest немного сложнее, но дает вам путь больше контроля)
+0

Я должен использовать POST, потому что мой объект запроса «не подходит» в методе GET. В любом случае я изменил реализацию на явный вызов SendAsync – koruyucu

+0

@koruyucu Да, это может быть сложно. Обычный способ решить этот REST-полностью будет заключаться в использовании, например, 'PUT', чтобы направить ваш объект запроса на сервер, который вернет вам URL-адрес« GET », чтобы получить ответ. Но это, вероятно, создаст больше проблем, чем решает: D – Luaan

+1

@ Luaan, потому что он решит * ничего *, чтобы быть ясным :) – usr

Смежные вопросы