How To Fix JSON.NET Circular References ($ref) In JavaScript

Yumasoft - how to solve JSON.NET circular references, featured photo

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:

JSON result from ASP.NET controller with $ref: "1" instead of a real object. Example of JSON.NET circular references

But what you actually want is the real object present there:

JSON result from ASP.NET controller with $ref: "1" replaced with a real object's content

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:

JSON result from ASP.NET controller with $ref: "1" instead of a real object

$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.

I struggled with this issue some time ago in my JavaScript code. In the beginning, I had no idea it might come from the fact that JSON.NET is used for serialization (thanks to our colleague Rafał for pointing that out to me ?). Let’s see what exactly happens here and why.

JSON.NET serialization

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.

However, if such JSONs are sent to the browser, fields with refs are of no use. We need the actual objects to be there, so we can process the results correctly using JavaScript.

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 None:

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).

Solution 2: resolve circular references using JavaScript

So we are back to this state in JavaScript:

JSON result from ASP.NET controller with $ref: "1" instead of a real object

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:

JSON result from ASP.NET controller with $ref: "1" instead of a real object

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:

JSON result from ASP.NET controller using JSON.NET without JSON.NET circular references

Wohhooa! That’s what we wanted ? There are no circular references in our JSON response anymore!

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x