I am using the System.Net.Http.HttpClient
to do some client-side HTTP communication. I've got all of the HTTP in one spot, abstracted away from the rest of the code. In one instance I want to read the response content as a stream, but the consumer of the stream is well insulated from where the HTTP communication happens and the stream is opened. In the spot responsible for HTTP communication I am disposing of all of the HttpClient
stuff.
This unit test will fail at 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 }
I typically try to dispose of anything IDisposable
at the earliest possible convenience but in this case, disposing the HttpResponseMessage
also disposes the Stream
returned from ReadAsStreamAsync
.
So it seems like the calling code needs to know about and take ownership of the response message as well as the stream, or I leave the response message undisposed and let the finalizer deal with it. Neither option feels right.
This answer talks about not disposing the HttpClient
. How about the HttpRequestMessage
and/or HttpResponseMessage
?
Am I missing something? I am hoping to keep the consuming code ignorant of HTTP but leaving all these undisposed objects around goes against year of habit!
The safest, general advice would be to always dispose of the HttpResponseMessage once you have finished with using it. This does lead to a little more code noise but ensures that regardless of the internals and any future changes, your code will free/clean up unused resources such as connections as quickly as possible.
Content . It does not dispose of response. RequestMessage or the HttpRequestMessage in any other way. It, therefore, does not dispose of the HttpRequestMessage.
So it seems like the calling code needs to know about and take ownership of the response message as well as the stream, or I leave the response message undisposed and let the finalizer deal with it. Neither option feels right.
In this specific case, there are no finalizers. Neither HttpResponseMessage
or HttpRequestMessage
implement a finalizer (and that's a good thing!). If you don't dispose of either of them, they will get garbage collected once the GC kicks in, and the handle to their underlying streams will be collected once that happens.
As long as you're using these objects, don't dispose. Once done, dispose of them. Instead of wrapping them in a using
statement, you can always explicitly call Dispose
once you're done. Either way the consuming code doesn't need to have any knowledge underlying http requests.
You can also take stream as input parameter, so the caller has complete control over type of the stream as well as its disposal. And now you can also dispose httpResponse before control leaves the method.
Below is the extension method for 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); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With