using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public Document() { this.MyObjects = new List<Child>(); }
public List<Child> MyObjects { get; set; }
readonly Document parent;
public Child(Document parent)
public string Foo { get; set; }
public string Bar { get; set; }
public Document GetParent() { return parent; }
public class DocumentContractResolver : DefaultContractResolver
ThreadLocal<Stack<Document>> ActiveDocuments = new ThreadLocal<Stack<Document>>(() => new Stack<Document>());
protected override JsonContract CreateContract(Type objectType)
var contract = base.CreateContract(objectType);
CustomizeDocumentContract(contract);
CustomizeMyObjectContract(contract);
void CustomizeDocumentContract(JsonContract contract)
if (typeof(Document).IsAssignableFrom(contract.UnderlyingType))
contract.OnDeserializingCallbacks.Add((o, c) => ActiveDocuments.Value.Push((Document)o));
contract.OnDeserializedCallbacks.Add((o, c) => ActiveDocuments.Value.Pop());
void CustomizeMyObjectContract(JsonContract contract)
if (typeof(Child) == contract.UnderlyingType)
contract.DefaultCreator = () => new Child(ActiveDocuments.Value.Peek());
contract.DefaultCreatorNonPublic = false;
public static void Test()
var inputDoc = new Document();
inputDoc.MyObjects.Add(new Child(inputDoc) { Foo = "foo", Bar = "bar" });
var contractResolver = new DocumentContractResolver();
var settings = new JsonSerializerSettings
ContractResolver = contractResolver,
var jsonString = JsonConvert.SerializeObject(inputDoc, Formatting.Indented, settings);
Console.WriteLine(jsonString);
var document = JsonConvert.DeserializeObject<Document>(jsonString, settings);
Assert.IsTrue(document.MyObjects.All(o => o.GetParent() == document));
var json2 = JsonConvert.SerializeObject(document, Formatting.Indented, settings);
Console.WriteLine(json2);
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(jsonString), JToken.Parse(json2)));
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");