从 ReadAsStreamAsync 传递 Stream 作为 API 响应并避免占用大量内存对象

DGi*_*bbs 5 .net c# asp.net stream asp.net-core-webapi

我正在使用两个 API,它们用于从外部系统下载大型文档。

我使用有关要检索的文档的一些信息调用 API 1,然后 API 1 使用充当“中间人”的相同信息调用 API 2。API 1 获取文档二进制文件,然后将其传递给原始调用者。

我想避免的是创建代表这些文档的大量内存对象,并仅传递一个流作为响应,这可以通过所描述的设置(“中间人”API)实现吗?

我所拥有的基本示例(在 API 1 中):

var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com/api/getdocs");
request.Content = parameters;

// 'ResponseHeadersRead' - indicate completion on reading of headers and not entire response...
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

if (response.StatusCode == HttpStatusCode.OK)
{
     var stream = await response.Content.ReadAsStreamAsync();

     return this.Ok(stream);
}
else
{
    // Logging/error handling...
}
Run Code Online (Sandbox Code Playgroud)

原始调用者将其响应作为流读取,然后传递给FileStreamResult在客户端计算机上下载文档的 a。

我的问题:

  • var stream = await response.Content.ReadAsStreamAsync()行是否仍在创建一个代表文档的大内存对象?
  • 上面的流是否需要被处理,或者底层会HttpContent负责清理流吗?如果确实需要处理它,我该如何在仍然将流响应传递给调用者的同时执行此操作?(这可能吗?)

Cha*_*ace 2

stream您传递给的内容Ok不应丢弃。Ok将包装流并将其作为对客户端的响应反馈回来,因此如果您处置它,则响应将失败。

从技术上讲,至少根据IDisposable咒语,你应该处置response. 但是,这样做会导致它也处置流,因此您不应该处置其中response任何一个。

不要担心它会导致任何内容泄漏:HttpResponseMessage除了内容流之外不会处理任何内容。请参阅下面的源代码

     protected virtual void Dispose(bool disposing)
     {
         // The reason for this type to implement IDisposable is that it contains instances of types that implement
         // IDisposable (content). 
         if (disposing && !disposed)
         {
             disposed = true;
             if (content != null)
             {
                 content.Dispose();
             }
         }
     }
Run Code Online (Sandbox Code Playgroud)

但是,您应该request使用using块进行处置,尽管在您的情况下,这也只是处置内容parameters