序列化和反序列化HttpRequestMessage对象

9

有人在对HttpRequestMessage对象进行序列化方面有经验吗?我试过使用Json.net,部分功能可行。但是,由于StringContent的构造问题,JsonConvert.DeserializeObject失败,报错"无法找到用于类型System.Net.Http.StringContent的构造函数"。

这里的应用场景简而言之就是我想保存网络请求并在以后发出它,在暂时的网络问题或服务不可用等情况下使用。

以下是示例代码:

var request = new HttpRequestMessage(HttpMethod.POST, "http://www.something.com");
request.Headers.Date = DateTimeOffset.UtcNow;
request.Headers.AcceptLanguage.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("en-US"));
request.Content = new StringContent("Hello World!");
request.Content.Headers.Add("x-some", "thing");                       

var result = JsonConvert.SerializeObject(request, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
});

var deserializeRequest = JsonConvert.DeserializeObject<HttpRequestMessage>(result, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects
}); 
3个回答

3

您可以使用以下示例代码将HttpRequest的相关部分进行序列化/反序列化。

var request = new HttpRequestMessage(HttpMethod.Post, "http://www.something.com");
request.Content = new StringContent("Hello World!");

var serializedRequestByteArray = new HttpMessageContent(request).ReadAsByteArrayAsync().Result;

var tmpRequest = new HttpRequestMessage();
tmpRequest.Content = new ByteArrayContent(serializedRequestByteArray);
tmpRequest.Content.Headers.Add("Content-Type", "application/http;msgtype=request");

var deserializedRequest = tmpRequest.Content.ReadAsHttpRequestMessageAsync().Result;  

2
关于这个解决方案需要注意的一点是,如果有的话,它将丢失HTTP方案和凭据。因此,在反序列化时,HTTPS将变为HTTP,没有任何凭据... - dstj
@dstj 您所指的凭据是什么? - Tóth Tibor
可以作为URL的一部分的可选凭据,例如https://username:password@server.example.com - dstj

2
我建议只对那些在您自己的代码库中维护实现的对象进行序列化。
对于HttpRequestMessage,不尝试对其进行序列化的原因之一是它实现了IDisposable接口,这意味着它可能持有对未托管资源的引用。使用序列化器很难预测它的行为。
在这种情况下,我更倾向于使用构建器模式。
var builder = new MyRequestBuilder()
    .SetUrl("http://www.something.com")
    .SetMethod("POST")
    .SetStringContent("My content")
    .DefaultRequestSettings() // One benefit you can encapsulate some logic in builder.

// ...

using(HttpRequestMessage requestMessage = builder.Build(DateTime.UtcNow)) // probably need to renew Date header upon issuing the actual request
{
   // issue request
}

1
问题在于StringContent没有默认构造函数。因此,当Json.Net尝试创建一个新的StringContent时,它无法实现。我尝试编写自定义的JsonConverter来处理这个问题,但也行不通,因为似乎你无法访问您分配给StringContent的值。即:
public class StringContentConverter :JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(HttpContent).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader); //There's nothing in here that says "Hello World!".  The string content hides it.
    }
}

基本上,您需要将HttpRequest消息的输入存储在自己的自定义类中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接