dka*_*man 37 .net c# idisposable stream dotnet-httpclient
我正在使用它System.Net.Http.HttpClient
做一些客户端HTTP通信.我在一个地方得到了所有的HTTP,从其余的代码中抽象出来.在一个实例中,我想将响应内容作为流读取,但是流的使用者与HTTP通信发生的位置以及流被打开的情况很好地隔离.在负责HTTP通信的地方我处理所有的HttpClient
东西.
此单元测试将失败Assert.IsTrue(stream.CanRead)
:
[TestMethod]
public async Task DebugStreamedContent()
{
Stream stream = null; // in real life the consumer of the stream is far away
var client = new HttpClient();
client.BaseAddress = new Uri("https://www.google.com/", UriKind.Absolute);
using (var request = new HttpRequestMessage(HttpMethod.Get, "/"))
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
//here I would return the stream to the caller
stream = await response.Content.ReadAsStreamAsync();
}
Assert.IsTrue(stream.CanRead); // FAIL if response is disposed so is the stream
}
Run Code Online (Sandbox Code Playgroud)
我通常会IDisposable
尽可能方便地处理任何东西,但在这种情况下,处理它HttpResponseMessage
也会处理Stream
退回的东西ReadAsStreamAsync
.
所以看起来调用代码需要了解并获取响应消息以及流的所有权,或者我将响应消息保留为不受限制并让终结器处理它.这两种选择都不对.
这个答案谈到不处理HttpClient
.怎么样HttpRequestMessage
和/或HttpResponseMessage
?
我错过了什么吗?我希望保持消费代码不知道HTTP,但留下所有这些不受约束的对象违背了一年的习惯!
Yuv*_*kov 12
所以看起来调用代码需要了解并获取响应消息以及流的所有权,或者我将响应消息保留为不受限制并让终结器处理它.这两种选择都不对.
在这种特定情况下,没有终结器.既没有HttpResponseMessage
或HttpRequestMessage
实现终结者(这是一件好事!).如果你不处理它们中的任何一个,它们将在GC启动后收集垃圾,并且一旦发生这种情况就会收集其底层流的句柄.
只要您使用这些物品,请不要丢弃.完成后,处理它们.using
您可以Dispose
在完成后始终显式调用,而不是将它们包装在语句中.无论哪种方式,消费代码都不需要具有任何基于http请求的知识.
您还可以将流作为输入参数,因此调用者可以完全控制流的类型以及它的处置.现在你也可以在控制离开方法之前配置httpResponse.
下面是HttpClient的扩展方法
public static async Task HttpDownloadStreamAsync(this HttpClient httpClient, string url, Stream output)
{
using (var httpResponse = await httpClient.GetAsync(url).ConfigureAwait(false))
{
// Ensures OK status
response.EnsureSuccessStatusCode();
// Get response stream
var result = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
await result.CopyToAsync(output).ConfigureAwait(false);
output.Seek(0L, SeekOrigin.Begin);
}
}
Run Code Online (Sandbox Code Playgroud)
在.NET中处理Dispose既容易又困难。当然。
流也拉扯了同样的废话...处置Buffer是否还会随后自动处置其包装的Stream?应该是?作为消费者,我是否应该知道呢?
当我处理这些东西时,我会遵循一些规则:
因此,您有了一个HttpClient,一个HttpRequestMessage和一个HttpResponseMessage。必须尊重它们每个生命周期以及它们制成的任何一次性用品。因此,永远不要期望您的Stream在HttpResponseMessage的Dispoable生命周期之外生存,因为您没有实例化Stream。
在上述情况下,我的模式是假装获取该Stream实际上只是在Static.DoGet(uri)方法中,并且您返回的Stream必须是我们自己创建的。这意味着第二个流,带有HttpResponseMessage的流.CopyTo'd我的新流(通过FileStream或MemoryStream路由或最适合您的情况的路由)...或类似的东西。因为:
因此,请使用一次性使用的物品,例如“抓取并释放”……制作它们,自己抓取结果,并尽快释放它们。并且不要混淆优化的正确性,尤其是那些不是您自己编写的类。
归档时间: |
|
查看次数: |
15204 次 |
最近记录: |