Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialize and deserialize HttpRequestMessage objects

Anyone have experience on serializing HttpRequestMessage objects? Trying with Json.net and it partially works. That said, JsonConvert.DeserializeObject fails due to constructure issues StringContent: "Unable to find a constructor to use for type System.Net.Http.StringContent".

The use case here is in short that I want to save the web request and issue it later, in case of temporary network issues or service unavailability etc..

Example code that is failing:

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
}); 
like image 906
Oddleif Avatar asked Oct 28 '14 14:10

Oddleif


2 Answers

I would suggest serializing only those objects for which you maintain implementation in your own codebase.

For HttpRequestMessage one of the reasons not to try serializing it is the fact it implements IDisposable, that means it can hold references to unmanaged resources. You can hardly predict it's behaviour with serializers.

In this case i'd better go with a builder pattern:

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
}
like image 159
George Polevoy Avatar answered Sep 22 '22 16:09

George Polevoy


It's possible to serialize/deserialize the relevant parts of an HttpRequest using the following example code.

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;  
like image 27
Oddleif Avatar answered Sep 24 '22 16:09

Oddleif