我正在使用 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
}
通常,我会尽早处理任何 IDisposable
对象,但在这种情况下,处理 HttpResponseMessage
对象也会处理从 ReadAsStreamAsync
方法返回的 Stream
。
所以,似乎调用代码需要知道和接管响应消息以及流,或者我将响应消息保持未处理状态,让终结器处理它。两种选择都不对。
这个回答 讨论了不处理 HttpClient
的情况。那么 HttpRequestMessage
和/或 HttpResponseMessage
呢?
我有什么遗漏吗?我希望保持使用代码无需了解 HTTP,但是让所有这些未处理的对象存在与我多年养成的习惯相悖!
IDisposable
都需要被释放掉。 - T.S.async
本身没有任何关系。规则都是一样的:在使用完毕之前不要处理该对象。同步版本也适用于相同的事情。所以,在using
中使用返回的Stream
。如果您需要在创建请求的上下文之外使用Stream
,则必须设置一个不同的机制以在正确的时间处置它。 - Peter Dunihoclient
,所以如果你对此感到舒服,就不需要费心去处理其他的东西了。至于你提到的答案,请注意它只适用于你需要重复使用HttpClient
对象的情况;坦率地说,如果你想重复使用它,你肯定不会释放它。这个指导并没有说明是否可以通过终结器来让对象自动清理(在我看来,这是非常糟糕的做法)。 - Peter Duniho