Given the HttpResponseMessage, how can I read the content of the request?
Given 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 cannot find a way to get something useful from
response.RequestMessage.Content // a StringContent instance
I've looked at the property tree StringContent
, but I can't figure out how to get its contents as a regular string in a way that works in the viewport.
Any suggestions?
source to share
Analysis System.Net.Http.dll v2.2.29.0
with ILSpy shows that the System.Net.Http.HttpClientHandler.CreateResponseMessage
(initializing object HttpResponse
) does nothing with the corresponding one HttpRequest
.Content
. This means that if it was not null
in the first place, the content object itself should be available.
System.ObjectDisposedException
selected when an operation is performed on a placed object. What does "located facility" mean? System.Net.Http.StringContent
It is realized System.IDisposable
through their ancestor System.Net.Http.HttpContent
. So it actually means "a IDisposable
after the method call .Dispose()
.
Naturally, searching for users HttpContent.Dispose()
leads us to the culprit -System.Net.Http.HttpClient.SendAsync()
which calls System.Net.Http.HttpClient.DisposeRequestContent()
after the data is sent.
Now what to do. All it HttpContent.Dispose()
does is close the object streams and set a flag. However StreamContent
(or rather, its parent ByteArrayContent
) stores the data in a field.Content
- which is not affected by the layout!
Alas, both methods that read it directly are this protected
, and all public methods that use them check the flag first. So, the only way to read this with reflection (illustration 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 # it would look like this:
type(ByteArrayContent)
.GetField("content",BindingFlags.NonPublic|BindingFlags.Instance)
.GetValue(content)
source to share