Open cschuchardt88 opened 1 year ago
Okay, lets start with distilling your issue report to the essential code necessary to reproduce the problem:
var jobjectKeyValuePair = new KeyValuePair<JObject, JObject>(
new JObject { new JProperty("type", "foo"), new JProperty("value", 1) },
new JObject { new JProperty("type", "bar"), new JProperty("value", 2) }
);
//
// Creating this JObject instance with jobjectKeyValuePair as value for one of
// its properties goes kaboom!
//
var jo = new JObject
{
new JProperty("foobar", jobjectKeyValuePair)
};
The issue is in you using a data type like KeyValuePair that is not supported by JValue (well, it's not the real issue, but more on that below). When you pass a content object that's not a JToken (or derived from it) to a JProperty, that content object is basically wrapped in a JValue instance when the content object is not an IEnumerable. If the content object is an IEnumerable, then the elements of the IEnumerable are wrapped individually in JValue instances and put into an JArray instance. But JValue does not (and therefore neither JProperty) attempt to convert a given content object (or the elements of an IEnumerable passed as content object) if it is not one of the data types it supports. It requires the content object to be one of the supported data types.
And that's where the actual and real issue manifests: Newtonsoft.Json's documentation. Nowhere in its documentation could i find any mention of what is and what is not allowed to pass as content object to a JValue, and therefore as content to a JProperty. Only by studying its source code (specifically the JValue.GetValueType method here: https://github.com/JamesNK/Newtonsoft.Json/blob/0a2e291c0d9c0c7675d445703e51750363a549ef/Src/Newtonsoft.Json/Linq/JValue.cs). As said, i found nothing in Newtonsoft.Json's documentation that describes these restrictions on the data types usable as content objects for JValue/JProperty.
One workaround, as you found out, is avoiding the use of KeyValuePair as content object by simply serializing the KeyValuePair enumerable and deserializing/parsing the resulting json string into a JToken representation, thus the JToken representation being built never encountering unsupported KeyValuePair instances at all.
Another workaround that would perform better than serialization followed by deserialization/parsing would be to avoid KeyValuePair instances by "simply" creating JObject instances (with "key" and "value" properties) instead of KeyValuePairs in your converter.
Still, despite these workarounds, the documentation needs to be improved. Badly. But i don't hang my hopes up high for that to happen, sadly...
Source/destination types
expected Output
Expected behavior
See output
Actual behavior
Get Error
System.ArgumentException : Could not determine JSON object type for type System.Collections.Generic.KeyValuePair`2[Newtonsoft.Json.Linq.JObject,Newtonsoft.Json.Linq.JObject].
Steps to reproduce
This is a work around.