In my project, I use a custom ContractResolver
to apply dynamically a custom JSONConverter
on specific properties of my object types. I also use a custom ReferenceResolver
in order to keep track not only of in-file references but also of external ones (coming from other JSON files).
Since I have a custom JSONConverter
, I have to manually check the presence of $ref
in the JSON text and call my ReferenceResolver
to find the pointed object.
What I am trying to achieve now is to postpone the resolution of certain missing references. Let say we have the file json1.json which have a reference to json2.json file into it, but we didn't deserialize json2.json yet. So a missing reference entry has to be tracked in order to be fixed later.
Here is a small snippet about the handling of missing references.
public override MyObject? ReadJson(JsonReader reader, Type objectType, MyObject? existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.StartObject:
{
var jsonObj = JObject.Load(reader);
if (jsonObj.ContainsKey("$ref"))
{
var id = (string)jsonObj["$ref"]!;
var ret = serializer.ReferenceResolver!.ResolveReference(serializer, id) as MyObject;;
if (ret == null)
{
// unresolved reference
var missingObjectId = Guid.Parse(id); // <-- GUID to track
var memberPath = reader.Path; // <-- Current object property path to track
var currentObject = ???; // <-- Object with missing reference to track
StoreMissingReference(currentObject, memberPath, missinObjectId);
}
return ret;
}
return jsonObj.ToObject(objectType, serializer) as MyObject;
}
}
}
The problem here is to access the currently populated object. What I can see in the call stack is the IValueProvider
has a reference of the targetObject to set the value on it. But I am not sure what is the best approach with IValueProvider
. Create one from scratch and assign it inside the ContractResolver
?
Also right now I use the property member path from the reader for my missing reference, but I will change that and pass the MemberInfo from the ContractResolver to the JSONConverter constructor. It will be easier to set the value later with Reflection.
Thank you!