I\'m having a problem getting some data serialized correctly from my ASP.NET Web API controller using Newtonsoft.Json.
Here\'s what I think is going on -
I wrote a minimal program to test this. Here is my github: https://github.com/assafwo1/TestSerializeJsonObjects. Here is the code:
using Newtonsoft.Json;
using System.Diagnostics;
namespace TestSerializeJsonObjects
{
class Program
{
public class Node
{
public Node Next { get; set; }
}
static void Main(string[] args)
{
// create new node
var head = new Node();
// point its "next" field at itself
head.Next = head;
// this is now the smallest circular reference data structure possible
// assert that head next is head
Debug.Assert(head.Next == head);
// save to string
var s = JsonConvert.SerializeObject(head, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
// get from string
var head2 = JsonConvert.DeserializeObject<Node>(s, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
// assert that head2 next is head2
Debug.Assert(head2.Next == head2);
// done
}
}
}
Yes, using PreserveReferencesHandling.Objects
is really the best way to serialize an object graph with circular references, because it produces the most compact JSON and it actually preserves the reference structure of the object graph. That is, when you deserialize the JSON back to objects (using a library that understands the $id
and $ref
notation), each reference to a particular object will point to the same instance of that object, rather than having multiple instances with the same data.
In your case the problem is that your client side parser does not understand the $id
and $ref
notation produced by Json.Net, so the references are not being resolved. This can be fixed by using a javascript method to reconstruct the object references after deserializing the JSON. See here and here for examples.
Another possibility which might work, depending on your situation, is to set ReferenceLoopHandling
to Ignore
when serializing instead of setting PreserveReferencesHandling
to Objects
. This is not a perfect solution though. See this question for a detailed explanation of the differences between using ReferenceLoopHandling.Ignore
and PreserveReferencesHandling.Objects
.