using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Nodes;
using System.Text.Encodings.Web;
using Debug = System.Console;
public class JsonReferenceResolver : ReferenceResolver
private uint _referenceCount;
private readonly Dictionary<string, object> _referenceIdToObjectMap = new();
private readonly Dictionary<object, string> _objectToReferenceIdMap = new(ReferenceEqualityComparer.Instance);
public override void AddReference(string referenceId, object value)
Console.WriteLine("Add Ref: " + referenceId);
if (!_referenceIdToObjectMap.TryAdd(referenceId, value))
throw new JsonException();
public override string GetReference(object value, out bool alreadyExists)
Console.WriteLine("Get Ref: " + value);
if (_objectToReferenceIdMap.TryGetValue(value, out string? referenceId))
referenceId = _referenceCount.ToString();
_objectToReferenceIdMap.Add(value, referenceId);
public override object ResolveReference(string referenceId)
Console.WriteLine("Res Ref: " + referenceId);
if (!_referenceIdToObjectMap.TryGetValue(referenceId, out object? value))
throw new JsonException();
public class JsonReferenceHandler : ReferenceHandler
public JsonReferenceHandler() => Reset();
private ReferenceResolver? _rootedResolver;
public override ReferenceResolver CreateResolver() => _rootedResolver!;
Debug.WriteLine("{0}.{1} called, stack trace =\n{2}", GetType().Name,System.Reflection.MethodBase.GetCurrentMethod()?.Name, new System.Diagnostics.StackTrace());
_rootedResolver = new JsonReferenceResolver();
public string Value { get; set; } = "";
private static ReferenceHandler referenceHandler = new JsonReferenceHandler();
private static readonly JsonSerializerOptions options = new()
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
ReferenceHandler = referenceHandler,
public static void Test()
public static void TestWithoutReset()
var model = new Model { Value = "hello" };
var array = new [] { model, model, model };
Assert.That(array.Distinct().Count() == 1);
var json = JsonSerializer.Serialize(array, options);
var deserializedArray = JsonSerializer.Deserialize<Model []>(json, options);
Assert.That(deserializedArray?.Length == array.Length);
Assert.That(deserializedArray!.Distinct().Count() == 1);
Assert.That(array.Distinct().Count() == 1);
Assert.That(Regex.Matches(json, model.Value).Count == 1);
public static void TestWithReset()
var model = new Model { Value = "hello" };
var array = new [] { model, model, model };
Assert.That(array.Distinct().Count() == 1);
((JsonReferenceHandler?)options.ReferenceHandler)?.Reset();
var json = JsonSerializer.Serialize(array, options);
((JsonReferenceHandler?)options.ReferenceHandler)?.Reset();
var deserializedArray = JsonSerializer.Deserialize<Model []>(json, options);
Assert.That(deserializedArray?.Length == array.Length);
Assert.That(deserializedArray!.Distinct().Count() == 1);
Assert.That(array.Distinct().Count() == 1);
Assert.That(Regex.Matches(json, model.Value).Count == 1);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");