分析使用
System.Net.Http.dll v2.2.29.0
和
ILSpy,发现
System.Net.Http.HttpClientHandler.CreateResponseMessage
(初始化
HttpResponse
对象的方法)并未对相应的
HttpRequest
的
.Content
进行任何操作。这意味着,如果一开始它不是
null
,那么
内容对象本身仍然可用。
System.ObjectDisposedException
会在"对已释放对象执行操作时"抛出。什么是"已释放对象"?System.Net.Http.StringContent
实际上是通过其祖先System.Net.Http.HttpContent
实现了System.IDisposable
接口。因此,它实际上意味着"在调用.Dispose()
方法后的IDisposable
对象"。
自然地,搜索HttpContent.Dispose()
的用户会将我们带到罪魁祸首-System.Net.Http.HttpClient.SendAsync()
,该方法在发送数据后调用System.Net.Http.HttpClient.DisposeRequestContent()
。
现在,关于该怎么做。所有
HttpContent.Dispose()
所做的就是关闭对象的流并设置标志。然而,
StreamContent
(或者它的父类
ByteArrayContent
)将数据保留在
.content
字段中 - 这个字段不会被处理!可惜的是,直接读取它的两种方法都是
protected
,所有使用这些方法的公共方法都首先检查标志。因此,读取它的唯一方法是通过反射(示例是用IronPython编写的,给出了C#等价物的注释):
>>> 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]>,
<...>
在C#中,它看起来像这样:
type(ByteArrayContent)
.GetField("content",BindingFlags.NonPublic|BindingFlags.Instance)
.GetValue(content)
HttpResponseMessage
获取请求体的内容? - Tomas Aschan