Search code examples
c#deserializationsystem.text.json

Json references during deserialization with custom ReferenceResolver get lost


I implemented a custom ReferenceResolver as shown from Microsoft

During serialization the $ids and $refs are added to the JSON correctly.

But during deserialization the $refs are not resolved.

This is my Resolver:

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))
        {
            alreadyExists = true;
        }
        else
        {
            _referenceCount++;
            referenceId = _referenceCount.ToString();
            _objectToReferenceIdMap.Add(value, referenceId);
            alreadyExists = false;
        }

        return referenceId;
    }

    public override object ResolveReference(string referenceId)
    {
        Console.WriteLine("Res Ref: " + referenceId);
        if (!_referenceIdToObjectMap.TryGetValue(referenceId, out object? value))
        {
            throw new JsonException();
        }

        return value;
    }
}

And this is my RefereceHandler:

public class JsonReferenceHandler : ReferenceHandler
{
    public JsonReferenceHandler() => Reset();
    private ReferenceResolver? _rootedResolver;
    public override ReferenceResolver CreateResolver() => _rootedResolver!;
    public void Reset(){
        _rootedResolver = new JsonReferenceResolver();
  }
}

and here I create the JsonSerializerOptions:

    private static ReferenceHandler referenceHandler = new JsonReferenceHandler();

    private static readonly JsonSerializerOptions options = new()
    {
        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
        WriteIndented = true,
        ReferenceHandler = referenceHandler,
        IncludeFields = true
    };

For serializsation:

JsonSerializer.SerializeToNode(objectToSave, options);

For deserialization:

JsonSerializer.Deserialize(typeconfigstring, options)

I added some console outputs to the methods of my custom resolver:

  • GetReference: is called during serialization.
  • AddReference: is called during deseialization, but not for all $ids, in the JSON.
  • ResolveReference: is never called.

Are I am doing something wrong?


Solution

  • Finally I found the mistake:

    I missed the private setter of my property, so during deserialization nothing was set.

    With a public setter or [JsonInlude] eyerything works like expected.