I am using .NET 8 and try to deserialize a class with a [JsonConstructor]
that has a Dictionary<string,int>
as parameter.
But this always fails with this error:
Reference metadata is not supported when deserializing constructor parameters.
I think this is because of the reference id "$id"
in the JSON:
"MyClass": {
"$id": "3",
"$type": "MyClassType",
"MyDictionary": {
"$id": "4",
"aaaa": 5661,
"bbbbb": 5661
}
}
This is my class:
public Dictionary<string, int> MyDictionary{ get; set; } = new();
[JsonConstructor]
private MyClass(Dictionary<string, int> MyDictionary)
{
this.MyDictionary= MyDictionary;
//...doing some other setup stuff
}
Is there any way to handle this without do write a custom converter?
If I do not use:
ReferenceHandler = ReferenceHandler.Preserve
this part works, but for my project I need to keep references.
2
Answers
You were on the right track in that $ represents metadata, not an actual data field. But the fix is actually to do this:
Set the metadata handling to ignore, and then you can serialize/deserialize the property using the PropertyName attribute:
This is the sample code:
The exception error message is self-explanatory:
ReferenceHandler.Preserve
does not work for types with parameterized constructors. System.Text.Json will throw an exception if you try to use it with a type with a parameterized constructor.I cannot find any place in the documentation where this is stated precisely, however in Preserve references and handle circular references MSFT writes:
While MSFT does not state this explicitly, it seems that any type with a parameterized constructor is considered to be immutable for the purposes of this limitation.
As a workaround, you will need to modify your class to have a parameterless constructor. Since your type is not in fact immutable (as your
MyDictionary
property has a setter), you could do so by moving the doing some other setup stuff setup logic into anIJsonOnDeserialized.OnDeserialized
callback, e.g. like so:Since
OnDeserialized()
will be called after theMyClass
instance is completely populated, you will be able to useMyDictionary
and any other needed properties for your setup.Demo fiddle here.