2015-10-07 2 views
10

Мы перенесли проект из WCF в Web API (SelfHost), и во время процесса мы заметили огромный спад при обслуживании веб-приложения. Теперь 40-50 секунд против 3 секунд ранее.ASP.NET Web API 2 - StreamContent чрезвычайно медленный

Я воспроизвести проблему в простой консольного приложения, добавляя различные NuGet Pacakges для AspNet.WebApi и OwinSelfHost со следующим контроллером:

var stream = new MemoryStream(); 
using (var file = File.OpenRead(filename)) 
{ 
    file.CopyTo(stream); 
} 
stream.Position = 0; 

var response = Request.CreateResponse(System.Net.HttpStatusCode.OK); 

/// THIS IS FAST 
response.Content = new ByteArrayContent(stream.ToArray()); 
/// THIS IS SLOW 
response.Content = new StreamContent(stream); 

response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(filename));    
response.Content.Headers.ContentLength = stream.Length; 

Как вы можете видеть из кода той лишь разницей, использование StreamContent (slooooow) и ByteArrayContent.

Приложение размещено на машине Win10 и доступно с моего ноутбука. Fiddler показывает, что для получения одного 1 МБ-файла с сервера на мой ноутбук с помощью StreamContent требуется 14 секунд, а ByteArrayContent - менее 1 с.

Также обратите внимание, что полный файл считывается в память, чтобы показать, что единственным отличием является класс содержимого.

Странная вещь, что кажется, что ее передача сама по себе медленная. Сервер отвечает заголовкам быстро/немедленно, но данные занимает много времени, чтобы прийти, как показано на Скрипач синхронизации информации:

GotResponseHeaders: 07:50:52.800 
ServerDoneResponse: 07:51:08.471 

Полная Timing Info:

== TIMING INFO ============ 
ClientConnected: 07:50:52.238 
ClientBeginRequest: 07:50:52.238 
GotRequestHeaders: 07:50:52.238 
ClientDoneRequest: 07:50:52.238 
Determine Gateway: 0ms 
DNS Lookup:   0ms 
TCP/IP Connect:  15ms 
HTTPS Handshake: 0ms 
ServerConnected: 07:50:52.253 
FiddlerBeginRequest:07:50:52.253 
ServerGotRequest: 07:50:52.253 
ServerBeginResponse:07:50:52.800 
GotResponseHeaders: 07:50:52.800 
ServerDoneResponse: 07:51:08.471 
ClientBeginResponse:07:51:08.471 
ClientDoneResponse: 07:51:08.471 

Overall Elapsed: 0:00:16.233 

Кто-нибудь знает, что происходит под капотом, который мог бы объяснить разницу в поведении?

+0

привет, я столкнулся с такой же проблемой здесь. вы нашли решение тем временем? – DanielG

+1

@ DanielG: Боюсь, что нет, но я разместил здесь отчет об ошибке: https://connect.microsoft.com/VisualStudio/feedback/details/1932717/asp-net-bug-issue. Было бы хорошо, если бы вы проголосовали за него, а также нажали ссылку «Я тоже могу» (рядом с «Репро»). – TommyN

+0

Хорошо, сделаю это. Один вопрос: почему бы вам не использовать только ByteArrayContent, если у вас уже есть данные уже в памяти? – DanielG

ответ

14

Решение моей проблемы для самостоятельного хостинга OWIN было размером буфера StreamContent. По умолчанию конструктор StreamContent использует значение по умолчанию 0x1000, 4Kb. В гигабитной сети передача 26 Мб файла занимает ~ 7 минут, чтобы завершить со скоростью ~ 60 Кбит/с.

const int BufferSize = 1024 * 1024; 
responseMessage = new HttpResponseMessage(); 
responseMessage.Content = new StreamContent(fileStream, BufferSize); 

Изменение размера буфера до 1 Мб занимает всего несколько секунд, чтобы завершить загрузку.

[EDIT] В StreamContent SerializeToStreamAsync делает StreamToStreamCopy, в соответствии с this link производительность будет отличаться. Подходящее значение, вероятно, составляет 80K.

0

Когда вы выполняете проекты, попробуйте перейти от отладки к выпуску. это длинный выстрел, который был бы удручающе увеличил бы производительность немного

+1

Нет разницы. Я боюсь. – TommyN

3

Я столкнулся с той же проблемой здесь, и я думаю, что это связано с самим хостингом Owin. Я просто создал образец приложения Asp.net и разместил его на IIS. В этом случае он работал, как ожидалось.

Результаты на моем Testsystem во время загрузки файла 80 MB:

  • с Streamcontent и SelfHosting: ~ 20 минут
  • с ByteArrayContent и Selfhosting: < 30 секунд
  • с Streamcontent и IIS хостинг: < 30 секунд

Либо есть параметр конфигурации в ASP.net, который мне не хватает в моем собственном хостинге ject, или есть ошибка в коде самообслуживания owin, я думаю.