Reputation: 76597
I'm currently working on a proof-of-concept and ran into an issue involving using JSON to serialize an HttpRequest.
Background
I originally thought that I would be able to easily accomplish it using the JSON.Encode() method as seen below :
JSON.Encode(HttpContext.Request)
However, I quickly found that this causes all sorts of circular references to be thrown (primarily due to the actual structure and complexity of the Request object). These only occur when actually encountering properties that do contain a circular reference, as I have previously used the following code to grab just specific elements that I need :
JSON.Encode(new {HttpContext.Request.Cookies,HttpContext.Request.Headers, ... });
which works just fine.
I'm just curious if there is a better method of handling this (or what the best method of handling it may be). I'll detail a few of the approaches that I have taken so far below to possibly find any areas that I may have gone wrong.
Previous Approaches
Using Reflection to iterate through each of the properties within the Request and attempting to construct a JSON string "property-by-property". (This failed when encountering a circular reference)
Attempting to store each of the Properties within a Dictionary object and then using JSON to serialize the entire Dictionary (in hopes that it would "flatten" the object out and make it easier to serialize)
Using the JSON.NET library and trying to serialize it through the JsonConvert.SerializeObject() method (I have tried to pass in several additional settings to avoid a circular reference, but haven't had any luck)
My latest approach (using the JSON.NET library) I thought would come close to working, however I encountered an error that involved a "Timeout" property on Stream objects within the Request.
I'm not opposed to simply avoiding serializing Stream objects and Circular References. I'm just trying to grab as much of the Request object as possible while avoiding any of these types of mishaps.
Upvotes: 15
Views: 23281
Reputation: 5526
I just attempted to do the same thing, I have now managed to get something serializing using JsonConvert with a contract resolver to ignore all the problem properties - I used this line to do the serialization:
string reqStr = JsonConvert.SerializeObject(context.Request,
Formatting.Indented, new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new IgnoreErrorPropertiesResolver()
});
And here's the contract resolver code I used:
public class IgnoreErrorPropertiesResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (["InputStream",
"Filter",
"Length",
"Position",
"ReadTimeout",
"WriteTimeout",
"LastActivityDate",
"LastUpdatedDate",
"Session"
].Contains(property.PropertyName)) {
property.Ignored = true;
}
return property;
}
}
This will need Newtonsoft.Json.Serialization
and System.Reflection
usings.
It happens I can't include the Session
object where I am, so that's in my list of ignored properties - obviously remove that if you can include it!
Upvotes: 10
Reputation: 303
I have used JsonConvert.SerializeObject
in my project and it is working fine. It seems it may solve your problem.
JsonConvert.SerializeObject(reqObject)
Upvotes: 3
Reputation: 5009
Any particular reason why you aren't using JSON.Net? It has a setting on it called PreserveReferencesHandling
, which tags objects with an additional property ("$id":"##"). If that object appears in the serialization more than once, instead of writing the object again it replaces it with "$ref": "##" pointing to the already existing json for the object. This circumvents circular referencing.
I've never tried returning JSON in that format to an $.ajax call so I don't know what would be involved in parsing it web-side.
Upvotes: 6