ASP.NET Web API 2 - StreamContent is extremely slow

本文关键字:StreamContent is extremely slow NET Web API ASP | 更新日期: 2023-09-27 18:16:21

我们已经将一个项目从WCF移植到Web API (SelfHost),在这个过程中,我们注意到在提供Web应用程序时出现了巨大的减速。现在是40-50秒,而之前是3秒。

我在一个简单的控制台应用程序中通过为asp.net添加各种Nuget包再现了这个问题。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显示,使用StreamContent从服务器到笔记本电脑获取单个1MB文件需要14秒,而ByteArrayContent少于15秒。

还要注意,完整的文件被读入内存,以表明唯一的区别是所使用的Content类。

奇怪的是,似乎是传输本身很慢。服务器快速/立即响应报头,但数据需要很长时间才能到达,如Fiddler定时信息所示:

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

Complete 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

有谁知道背后发生了什么可以解释行为上的差异吗?

ASP.NET Web API 2 - StreamContent is extremely slow

我的OWIN自托管问题的解决方案是StreamContent缓冲区大小。StreamContent的默认构造函数使用默认值0x1000,4kb。在千兆网络上,以60Kb/s的速率传输26Mb的文件需要约7分钟。

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

将bufferSize修改为1Mb现在只需几秒钟即可完成下载。

[EDIT]在StreamContent SerializeToStreamAsync做一个StreamToStreamCopy,根据这个链接的性能会有所不同。一个合适的值可能是80K。

我在这里面临同样的问题,我认为这与自己的自我托管有关。我刚刚创建了一个Asp.net示例应用程序,并将其托管在IIS上。在这种情况下,它像预期的那样起作用了。

在我的Testsystem上下载一个80mb文件的结果:

  • 与流内容和自我托管:~20分钟
  • 与ByteArrayContent和Selfhosting: <30秒
  • 带有流内容和IIS主机的
  • : <30秒

要么是我在自托管项目中缺少的ASP.net配置设置,要么是我自己的自托管代码中存在错误。

在编译项目时,尝试从调试更改为发布。这是一个很渺茫的机会,但肯定会提高性能。