【问题标题】:WebAPI Request Streaming supportWebAPI 请求流支持
【发布时间】:2023-06-10 10:39:01
【问题描述】:

我正在编写一个 ASP.NET Web API 应用程序,它要求我接受文件上传并将该文件转发到另一个 HTTP 端点。

我担心如果许多用户尝试每个人上传一个 100MB 的文件(这是一个有效的用例),那么我的应用程序将占用大量内存,并且根据大型请求的数量,这个占用量可能会变得很大,而我的应用程序会崩溃并死掉。

理想情况下,我希望在 Web 服务器开始接收文件后立即开始将文件流式传输到另一个 HTTP 端点,以显着减少服务器上的负载。

我确定这个过程有一个名字,但我不知道 - 这使得搜索它变得相当困难。

我已经对 Web API 中的响应流式处理做了很多工作,但我以前从未考虑过请求流式传输。

尽我所能告诉我我需要弄清楚如何:

  • 在完成上传之前开始处理流。
  • 使用 HttpClient 流式传输相同的请求以将相同的数据流式传输到另一个 HTTP 端点。

谁能给我一些建议?

【问题讨论】:

  • 您最终使用了什么 MultipartStreamProvider 来实现这一点?我正在努力实现完全相同的目标......你能分享你的控制器代码吗?

标签: c# asp.net streaming asp.net-web-api


【解决方案1】:

这是一个有趣的问题。我会尽力提供一些一般性的指示。

需要考虑的几件事:

1) 默认情况下,Web API 会缓冲请求,因此您担心内存占用量可能会很大,这绝对是有道理的。您可以强制 Web API 以流模式处理请求:

    public class NoBufferPolicySelector : WebHostBufferPolicySelector
    {
       public override bool UseBufferedInputStream(object hostContext)
       {
          var context = hostContext as HttpContextBase;

          if (context != null)
          {
             if (string.Equals(context.Request.RequestContext.RouteData.Values["controller"].ToString(), "uploading", StringComparison.InvariantCultureIgnoreCase))
                return false;
          }

          return true;
       }

       public override bool UseBufferedOutputStream(HttpResponseMessage response)
       {
          return base.UseBufferedOutputStream(response);
       }
    }

然后替换服务:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHostBufferPolicySelector), new NoBufferPolicySelector());

请注意,由于此时 WebHost 和 SelfHost 之间存在差异,因此只能在 WebHost 中进行此类更改。如果您的端点是 selfHosted,则必须在 GlobalConfig 级别设置流模式:

//requests only
selfHostConf.TransferMode = TransferMode.StreamedRequest;
//responses only
selfHostConf.TransferMode = TransferMode.StreamedResponse;
//both
selfHostConf.TransferMode = TransferMode.Streamed;

我之前曾在博客上详细介绍过如何在 Web API 中处理大文件 - http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ 所以希望你会发现它很有用。

2) 其次,如果您使用HttpClient,在.NET 4 中它默认缓冲请求正文,因此您应该真正使用.NET 4.5。

如果您必须使用 .NET 4,您必须直接使用 HttWebRequest: - http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowreadstreambuffering.aspx - http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowwritestreambuffering.aspx

3) 就将数据推送到客户端而言,如果您想这样做,这绝对是可能的,使用PushStreamContent。 Henrik 在这里有一篇简短的介绍性帖子 - http://blogs.msdn.com/b/henrikn/archive/2012/04/23/using-cookies-with-asp-net-web-api.aspx(它基于 Web API RC 位,因此您可能需要调整一些签名等) 我还写了关于在这里推送大块流数据的博客 - http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/

编辑:要查看请求中 PushStreamContent 的示例,您可以查看此示例解决方案 - http://aspnet.codeplex.com/SourceControl/changeset/view/bb167f0b0013#Samples/Net45/CS/WebApi/UploadXDocumentSample/ReadMe.txt

【讨论】:

  • 我没有意识到在发出请求时我可以使用 PushStreamContent。我只在回复中使用过它们。幸运的是,我们使用的是 .NET 4.5 - 那么这是否意味着 HttpClient 不会缓冲请求?
  • 是 - .NET 4.5 中的 HttpClient 默认情况下不缓冲请求。在 .NET 4 中确实如此(意味着将整个请求加载到内存中,然后发送)。
  • 我在响应中添加了一个示例引用(请求中的 PushStreamContent)
  • 根据您的回答实施了解决方案,并使用 PerfMon 对其进行了分析。一切看起来都很棒。 PerfMon 的数字令人大开眼界。谢谢(再次)。
  • 愿意分享您的解决方案吗?我似乎无法使用 Owin Web Hosted WebAPI 2 来完成这项工作。