Given a System.Net.Http.HttpResponseMessage
, I can get quite a lot of information about the request I made through response.RequestMessage
, for example
response.RequestMessage.RequestUri // the url of the request
response.RequestMessage.Method // the HTTP method
However, I can't figure out a way to get something useful from
response.RequestMessage.Content // a StringContent instance
I've looked through the property tree of the StringContent
, but I can't figure out how to get its contents as a regular string in a way that works in the Watch Window.
Any suggestions?
Analyzing System.Net.Http.dll v2.2.29.0
with ILSpy shows that System.Net.Http.HttpClientHandler.CreateResponseMessage
(that initializes an HttpResponse
object) doesn't do anything with the corresponding HttpRequest
's .Content
. That means that if it wasn't null
in the first place, the content object itself should still be available.
System.ObjectDisposedException
is thrown "when an operation is performed on a disposed object." What does a "disposed object" mean? System.Net.Http.StringContent
turns out to implement System.IDisposable
through its ancestor, System.Net.Http.HttpContent
.
So, it actually means "an IDisposable
after its .Dispose()
method was called."
Naturally, searching for HttpContent.Dispose()
users brings us to the culprit - System.Net.Http.HttpClient.SendAsync()
that calls System.Net.Http.HttpClient.DisposeRequestContent()
after sending the data.
Now, regarding what to do. All that HttpContent.Dispose()
does is close the object's streams and set a flag. However, StreamContent
(or rather its parent, ByteArrayContent
) keeps the data in the .content
field - which isn't touched by the disposition!
Alas, both methods that read it directly are protected
, and all the public methods that use those check the flag first. So, the only way to read it is with reflection (the illustration is in IronPython, notes are given for C# equivalents):
>>> sc=System.Net.Http.StringContent("abcdefghijklmnopqrstuvwxyz")
#in C#, the following is `type(StringContent)' (this is what it actually does)
>>> scd=System.Reflection.TypeDelegator(System.Net.Http.StringContent)
>>> print scd.GetField("content",System.Reflection.BindingFlags.NonPublic|System.Reflection.BindingFlags.Instance)
None #because the field is in ByteArrayContent and is private
>>> bacd=System.Reflection.TypeDelegator(System.Net.Http.ByteArrayContent)
>>> bacd.GetField("content",System.Reflection.BindingFlags.NonPublic|System.Reflection.BindingFlags.Instance)
<System.Reflection.RtFieldInfo object at 0x000000000000002C [Byte[] content]>
# `_' is last result
>>> _.GetValue(sc)
Array[Byte]((<System.Byte object at 0x000000000000002D [97]>, <System.Byte objec
t at 0x000000000000002E [98]>, <System.Byte object at 0x000000000000002F [99]>,
<...>
In C#, this would look like:
type(ByteArrayContent)
.GetField("content",BindingFlags.NonPublic|BindingFlags.Instance)
.GetValue(content)
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