9

The behavior of the HttpClient.PostAsync method is to dispose of the provided HttpContent object.

There are many ways to get around this behavior including constructing a new HttpContent for each call made on the client or loading the content to a stream and changing the pointer.

I'm wondering why invoking this method automatically invokes the disposal of its IDisposable parameters? As far as I'm aware this is not a common behavior in .NET

It's also worth noting that this behavior is observed in PUT requests as well, which are idempotent, so the premise that this behavior is to prevent the information from being sent again doesn't seem correct.

Matthew
  • 10,244
  • 5
  • 49
  • 104

1 Answers1

9

I couldn't immediately find the implementation on referencesource but the WCF source contains it as well. The method you're looking for is DisposeRequestContent(HttpRequestMessage) and the accompanying comment says this:

When a request completes, HttpClient disposes the request content so the user doesn't have to. This also ensures that a HttpContent object is only sent once using HttpClient (similar to HttpRequestMessages that can also be sent only once).

HttpContent content = request.Content;
if (content != null)
{
    content.Dispose();
}

Basically it's a safeguard to make sure you don't send the same response twice which they consider a bad/uncommon/discouraged use case.

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • 1
    I can *maybe* understand this behavior for `POST` calls, but the same behavior is observed for `PUT` requests which are idempotent; so the explanation about only sending it once doesn't make sense to me. – Matthew Aug 25 '14 at 22:58
  • 9
    @Matthew It also doesn't make sense to dispose if you call LoadIntoBufferAsync on the HttpContent. When I create derived HttpContent classes, I will often ensure that the Dispose method does nothing destructive so that I can safely reuse the content. Dispose originally was only supposed to be used for cleaning up unmanaged resources. I really don't like the fact that it is now being used for arbitrary cleanup. – Darrel Miller Aug 27 '14 at 14:44
  • Here's the only documentation I could find for this "convenience" feature, though I fail to see how it is convenient to do this and as far as I can tell not even officially document the behavior anywhere: https://github.com/dotnet/runtime/issues/14612 – user12861 Jul 05 '20 at 17:42
  • P.S. can you tell I wasted 4 hours on this? – user12861 Jul 05 '20 at 17:43
  • 1
    I just ran into this behavior while unit testing a multi-target project. Interestingly I do not get object disposed exceptions when the tests run against NetCore. I guess they fixed it? – kitsu.eb Aug 27 '20 at 20:12
  • 1
    Yes, they did: https://github.com/dotnet/corefx/pull/19082 – Efran Cobisi Jan 22 '21 at 11:28
  • I know where this behavior mentioned by the OP is useful and justified. When I call a method on HttpClient, e.g. PostAsync, and I am uploading a file using StreamContent object, I require that the latter's Dispose method be called by PostAsnyc. This will remove the burden from me in keeping a reference on the StreamContent object and calling it's Dispose method once the results of the PostAsnyc call is available. – ghd Jun 07 '21 at 07:18