(At the time of writing, the OP's question is ambiguous as to whether they're referring to HttpRequestMessage or HttpResponseMessage, so I'll describe both).
HttpRequestMessage.Dispose():
HttpResponseMessage.Dispose():
- Disposes of only its
response.Content.
- It does not dispose of
response.RequestMessage or the HttpRequestMessage in any other way.
- It, therefore, does not dispose of the
HttpRequestMessage.Content either.
- See the source code here.
You should not dispose of the HttpRequestMessage until after the HttpClient has fully finished sending your request (I believe there are some (rare) cases where you get a HttpResponseMessage back even if the request's content has not finished being sent yet - like when using exotic transfer-encoding schemes or multi-part requests) - but it's generally best to assume nested lifetimes of all objects involved, so _if System.Net.Http were perfect (which it isn't) then you'd do this:
- Ensure the request/response is fully completed.
- Dispose of the response content first.
- Then the
HttpResponseMessage.
- Then the request's content.
- Then the
HttpRequestMessage.
- Then the
HttpClient.
...however as disposing of content is implicit when you dispose of the parent request/response message (and you probably shouldn't call HttpClient.Dispose either), so just do this:
using (HttpClient httpClient = this.httpClientFactory.CreateHttpClient()) // Only dispose HttpClient instances created by IHttpClientFactory. *DO NOT DISPOSE* of other HttpClient instances unless you know what you're doing!
using (HttpContent reqContent = new StringContent("test")) // Disposing of this HttpContent is unnecessary (as it's disposed when `request` is disposed).
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = reqContent })
using (HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false)) // Note there is no `using()` block for the HttpContent object, this is because we don't "own" the object, the HttpResponseMessage does.
{
String responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return responseBody;
}
Though remember that the HttpRequestMessage and HttpResponseMessage objects are separate, so you can dispose of your HttpRequestMessage but still return the HttpResponseMessage (or vice-versa!) (though you cannot return the Stream from ResponseMessage.Content.ReadAsStream() if you do dispose of the HttpResponseMessage - so if you need to return a Stream you should subclass Stream and wrap the returned stream but don't dispose the HttpResponseMessage and instead dispose of it inside your Stream subclass's Dispose method.
public async Task<Stream> GetStreamAsync()
{
using( HttpClient httpClient = this.httpClientFactory.CreateHttpClient() )
using( HttpContent reqContent = new StringContent("test") )
using( HttpRequestMessage request = new HttpRequestMessage( HttpMethod.Post, requestUri) { Content = reqContent })
{
HttpResponseMessage response = await this.httpClient.SendAsync( request ).ConfigureAwait(false);
try
{
Stream stream = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return new StreamWithDependencies( stream, response ); // See `class StreamWithDependencies` below.
}
catch // <-- When returning an IDisposable you should only dispose of things in `catch`, not in a `finally`.
{
response.Dispose(); // <-- Doing this means `response` (and `response.Content` will always be disposed) *and* can optionally outlive the method's scope if it follows the happy-path.
throw; // <-- Don't swallow any exceptions, re-throw them (don't use `throw ex;` as that resets the StackTrace, always use either `throw;` (without a name) or throw a new exception with the caught exception passed as the `Exception.InnerException`.)
}
}
}
Here is an example of what class Stream2 could look like: the main points are that it proxies Stream, and that its Dispose method will dispose of other objects you tell it to.
using System.Collections.Immutable;
using System.IO;
class StreamWithDependencies : Stream
{
private readonly Stream subject;
private readonly ImmutableList<IDisposable> disposeWith;
public StreamWithDependencies( Stream subject, params IDisposable[] disposeWith )
{
this.subject = subject ?? throw new ArgumentNullException(nameof(subject));
this.disposeWith = ( disposeWith ?? Array.Empty<IDisposable>() ).ToImmutableList();
}
protected override void Dispose(Boolean disposing)
{
if( disposing )
{
this.subject.Dispose();
foreach( IDisposable d in this.disposeWith )
{
d.Dispose();
}
}
base.Dispose(disposing);
}
public override Int32 Read(...) => this.subject.Read( ... ):
pubiic override Task<Int32> ReadAsync( ... ) => this.Subject.ReadAsync( ... );
// etc
// Only implement and forward methods for reading, no need to implement methods for writing.
}