【问题标题】:MemoryStream from HttpContent without copying来自 HttpContent 的 MemoryStream 无需复制
【发布时间】:2020-06-30 04:03:56
【问题描述】:

我正在尝试将 System.Net.Http 用于 POST 请求。我可以接受 HTTP 响应正文在内存中,但需要为其获取 MemoryStream。一种方法是调用 HttpContent.GetAsByteArrayAsync() 并在其上包装一个 MemoryStream,但我认为这需要将内容复制到一个单独的字节数组中(因为它返回字节 [] 的任务)。

如果响应正文已经在 HttpContent 的某个内部缓冲区中,是否可以在该缓冲区之上创建 MemoryStream,或者以某种方式从 HttpContent 返回 MemoryStream 并避免复制到单独的字节数组?

还有 HttpContent.GetAsStreamAsync(),但它返回的是常规 Stream,而不是 MemoryStream。尽管它可能已经是 MemoryStream 的一个实例,但我认为将返回的流转换为 MemoryStream 是不安全的,也不是一种好的做法? (因为这是可能改变的实现细节)。

有没有其他方法可以做到这一点,还是我别无选择,只能先复制到 byte[] 中?

谢谢。

【问题讨论】:

    标签: c# http post .net-core system.net


    【解决方案1】:

    如果你先调用LoadIntoBufferAsyncReadAsStreamAsync 返回一个只读 MemoryStream

    await req.Content.LoadIntoBufferAsync();
    var stream = (MemoryStream) await req.Content.ReadAsStreamAsync();
    

    【讨论】:

    • 谢谢,这似乎是正确的方法,但是我找不到提到 ReadAsStreamAsync 将在调用 LoadIntoBufferAsync 后返回只读 MemoryStream 的文档。微软有没有关于这方面的文档或示例?
    • 我认为没有文档。如果您不信任该实现,您可以使用ReadAsByteArray() 并使用此构造函数public MemoryStream (byte[] buffer, bool writable); 创建一个MemoryStream。这就是HttpContent 在内部所做的。而且它不会复制缓冲区。
    • 谢谢,是的,从源代码来看,它确实返回了内存流。看起来这是在这种情况下最好的方法,但不确定这在未来的版本中是否可靠。我想确定我可以调用 ReadAsStreamAsync() 并检查实例是否为 MemoryStream,如果不是,则将返回的流复制到新的 MemoryStream 中。我认为 ReadAsByteArrayAsync 会复制缓冲区(至少在它调用 MemoryStream.ToArray() 进行复制的源代码中)。
    • 你可以有一个单元测试覆盖铸造位。如果您升级到新版本,则此行为已更改。你的单元测试会失败,你会知道的。
    【解决方案2】:

    如果您先调用LoadIntoBufferAsyncCopyToAsync 可用于填充只读 MemoryStream

    var stream = new MemoryStream(req.Content.Headers.ContentLength);
    await req.Content.LoadIntoBufferAsync((int)req.Content.Headers.ContentLength);
    await req.Content.CopyToAsync(stream);
    

    此实现不依赖于副作用,所有框架版本的文档都支持:https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpcontent.loadintobufferasync?view=netframework-4.6.2

    注意:我尝试编辑上述答案,但无法做到……所以你来了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-19
      相关资源
      最近更新 更多