If you work with a .NET backend that uses JSON.NET for serialization, you might encounter such weird things in the JSON result returned from a controller:
But what you actually want is the real object present there:
After reading this article, you will know how to achieve that 🙂
JSON.NET circular references are the issue
Let’s take a look at our problematic JSON response object once again:
$ref: "1" is basically a reference to another object, which has already been serialized. In that case, the
BestFriend field references the first element of the result array with
$id: "1". It turns out that these are JSON.NET circular references. However, you don’t want these references in your client-side JS code – you need the actual objects to work with.
The JS example presented above shows a JSON result received from the following ASP.NET controller method:
This is the full content of
json string after serialization:
Of course, this is great that JSON.NET does that. Why would we repeat the same objects multiple times in JSONs? The optimization here is that the same objects are serialized once and referenced from all places that use them.
Solution 1: fix the issue by reconfiguring JSON.NET serializer
The first obvious solution could be to configure JSON.NET to not use its optimization for references. Quickly searching through its documentation, we find that PreserveReferencesHandling setting is responsible for that.
If we change our controller’s code and serialize objects with
PreserveReferencesHandling set to
Our JSON file will look exactly as we’d expect:
However, why would we disable JSON.NET circular references? This optimization can sometimes save us huge amounts of data to be sent over the wire. If you have thousands of objects, it might not make sense in sending them all to the client-side code.
You may also have no control of the backend/API you receive the data from. It might as well be dangerous to change the JSON serialization settings, especially if you work on a big project.
If reconfiguration of JSON.NET circular references serialization is not possible in your case, see the other solution (which we also use).
What we want is to have the full objects’ contents instead of
$ref elements in our JSON result.
In fact, all the data we need is already there. The first element of the array with
$id: "1" is object that should be put in place of all
$ref: "1" references.
As you can imagine, this requires a mechanism that would traverse the results tree and replace all these values according to IDs of the referenced objects.
Fortunately, we don’t need to implement it ourselves. There are few implementations of such a tool, circulating the web.
We use something called
JsonNetDecycle which we found few years back already. I noticed there’s a new version of it ported to TypeScript: jsonNetDecycle.ts. It doesn’t provide full type support as it is a few years old already, and I didn’t try it. But you can if you use TypeScript 🙂 There’s also a
cycle.js solution available here and recommended by many folks. I believe it may also solve our issue, but again – this is not what we are using.
The version of the
JsonNetDecycle we use is this one. Simply create a new file called
JsonNetDecycle.js in your project and copy this Gist’s contents to this file. You can skip the last part starting with
(function(console) (line 112) – we won’t need it.
Now, we can use the exported
JsonNetDecycle.retrocycle() function to “fix” our JSON:
Let’s see whether this works.
This is what we get from the API before resolving JSON.NET circular references:
So we still have references there instead of real objects.
Now let’s see what happens with the
result object after executing
JsonNetDecycle.retrocycle() on it:
Wohhooa! That’s what we wanted 😎 There are no circular references in our JSON response anymore!