Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I disable object reference creation in the Newtonsoft JSON serializer?

I switched my ASP.NET MVC application to use the Newtonsoft JsonSerializer to do our JSON serialization, as such:

var writer = new JsonTextWriter(HttpContext.Response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create();
serializer.Serialize(writer, myData);

This generates some JSON that has $id and $ref properties and then removes duplicate objects from the JSON. I know it's a feature that is great, but the clients that read this JSON cannot support interpreting these references and expect full objects to be there. I've tried setting the PreserveReferencesHandling property on the JsonSerializerSettings to every possible value and it doesn't seem to make any difference.

How can I disable the creation of the $id and $ref properties and get the Newtonsoft serializer to write out the whole object graph?

EDIT: here is a sample C# class, the JSON I expect, and the JSON created by the Newtonsoft serializer:

public class Product
{
    public Image MainImage { get; set; }

    public List<Image> AllImages { get; set; }
}

public class Image
{
    public int Id { get; set; }
    public string Url { get; set; }
}

JSON I expect:

{
    MainImage: { Id: 1, Url: 'http://contoso.com/product.png' },
    AllImages: [{ Id: 1, Url: 'http://contoso.com/product.png' },{ Id: 2, Url: 'http://contoso.com/product2.png' }]
}

JSON created by the Newtonsoft serializer (note the added $id parameter in MainImage and the referenced object being completely replaced by a $ref parameter):

{
    MainImage: { $id: 1, Id: 1, Url: 'http://contoso.com/product.png' },
    AllImages: [{ $ref: 1 },{ Id: 2, Url: 'http://contoso.com/product2.png' }]
}

I understand that the Newtonsoft version is better (it's DRYer) but the client that reads this JSON output does not understand what $ref means.

like image 618
user2719100 Avatar asked Oct 11 '13 01:10

user2719100


People also ask

How do you preserve references and handle or ignore circular references in System text JSON?

To preserve references and handle circular references, set ReferenceHandler to Preserve. This setting causes the following behavior: On serialize: When writing complex types, the serializer also writes metadata properties ( $id , $values , and $ref ).

Is Newtonsoft JSON obsolete?

The Newtonsoft. Json. Schema namespace provides classes that are used to implement JSON schema. Obsolete.

Should I use Newtonsoft or System text JSON?

By default, Newtonsoft. Json does case insensitive property name matching during deserialization whereas System. Text. Json does case sensitive matching (with exception in ASP.Net core where you don't need to do anything to achieve behavior like Newtonsoft.

What is serializing in JSON?

Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted.


1 Answers

I see from your comments that your classes are actually decorated with [DataContract(IsReference = true)], so that explains why you are seeing the reference information getting added to your JSON. From the JSON.Net documentation on Serialization Attributes:

As well as using the built-in Json.NET attributes, Json.NET also looks for the SerializableAttribute (if IgnoreSerializableAttribute on DefaultContractResolver is set to false) DataContractAttribute, DataMemberAttribute and NonSerializedAttribute ... when determining how JSON is to be serialized and deserialized.

It also says this:

Note

Json.NET attributes take precedence over standard .NET serialization attributes, e.g. if both JsonPropertyAttribute and DataMemberAttribute are present on a property and both customize the name, the name from JsonPropertyAttribute will be used.

So, it seems the solution to your problem is simple: just add [JsonObject(IsReference = false)] to your classes like this:

[DataContract(IsReference = true)]
[JsonObject(IsReference = false)]
public class Product
{
    [DataMember]
    public Image MainImage { get; set; }
    [DataMember]
    public List<Image> AllImages { get; set; }
}

[DataContract(IsReference = true)]
[JsonObject(IsReference = false)]
public class Image
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Url { get; set; }
}

This will allow you to keep your WCF attributes in place, but will override the reference behavior when it is time to serialize to JSON.

like image 168
Brian Rogers Avatar answered Sep 27 '22 21:09

Brian Rogers