System.Text.Json exception thrown deserializing json. Json was serialized using the same framework version.
Reference '5' not found. Path: $.Test.$values[0].$ref | LineNumber: 34 | BytePositionInLine: 19.
Note: the two objects named 'Test' are separate instances.
{
"$id": "1",
"Root": {
"$id": "2",
"$values": [
{
"$id": "3",
"Id": "66968da1-17c4-4180-8a74-b3e3ee066e59",
"Name": "Root",
"Parent": null,
"Children": {
"$id": "4",
"$values": [
{
"$id": "5",
"Id": "6edc6837-1a73-4a67-9377-4b62684dfb29",
"Name": "Test",
"Parent": {
"$ref": "3"
},
"Children": {
"$id": "6",
"$values": []
}
}
]
}
}
]
},
"Test": {
"$id": "7",
"$values": [
{
"$ref": "5"
},
{
"$id": "8",
"Id": "b5ec04f5-f348-46dc-a5f0-44c95b181a72",
"Name": "Test",
"Parent": {
"$id": "9",
"Id": "222062ca-c4c5-4a5a-af9f-abeb89bcd8a5",
"Name": "Kent",
"Parent": null,
"Children": {
"$id": "10",
"$values": [
{
"$ref": "8"
}
]
}
},
"Children": {
"$id": "11",
"$values": []
}
}
]
},
"Kent": {
"$id": "12",
"$values": [
{
"$ref": "9"
}
]
}
}
net5.0 (dotnet-sdk-5.0.100-win-x64)
Windows 10 Pro 64bit
10.0.19042 Build 19042
public sealed class Link
{
[JsonInclude]
public Guid Id { get; }
[JsonInclude]
public string Name { get; }
[JsonInclude]
public Link Parent { get; }
[JsonInclude]
public List<Link> Children { get; }
public Link()
{
}
public Link(Link parent, string name)
{
Parent = parent;
Id = Guid.NewGuid();
Name = name ?? Id.ToString();
Children = new List<Link>();
}
}
Serialized object:
public Dictionary<string, List<Link>> Links { get; private set; } = new Dictionary<string, List<Link>>();
Deserializing code:
var jsonSerializerOptions = new JsonSerializerOptions
{
MaxDepth = 10000,
ReferenceHandler = ReferenceHandler.Preserve
};
if (!string.IsNullOrWhiteSpace(filename))
{
using Stream reader = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
Links = await JsonSerializer.DeserializeAsync<Dictionary<string, List<Link>>>(reader, jsonSerializerOptions);
}
Parent and Children need to have a setter in order to be properly deserialized; otherwise, the payload for those objects will be ignored and hence, the reference (in this case "5") not being saved.
@justcurious can you try adding a setter for those properties?
public sealed class Link
{
[JsonInclude]
public Link Parent { get; private set; }
[JsonInclude]
public List<Link> Children { get; private set; }
}
@Jozkee is there easy enough detection in the serializer to throw an exception when metadata comes in for a property that can't be set? Would it be beneficial? Just thinking of we can make the root cause of issues like this clearer to callers.
Thanks @Jozkee , that makes sense
@layomia I think that would imply replacing calls to Utf8JsonReader (Try)Skip method with a custom method that "reads and validates" when certain features, such as ReferenceHandler, are turned on.
Would it be beneficial?
Right now the only case that I can think that would benefit from it would be ReferenceHandler.Preserve and the only benefit I can see is better exception messages.
Most helpful comment
Parent and Children need to have a setter in order to be properly deserialized; otherwise, the payload for those objects will be ignored and hence, the reference (in this case "5") not being saved.
@justcurious can you try adding a setter for those properties?