Closed slavapvf closed 4 months ago
I suspect because of the position of $type property
Correct. By default, Newtonsoft.Json detects metadata keywords such as $type
only at the beginning of json objects (for performance and memory reasons).
In your situation, you need to explicitly instruct Newtonsoft.Json to read ahead in the json data to look for metadata keywords, at the cost of buffering json data during deserialization. This is done by setting the JsonSerializerSettings MetadataPropertyHandling
property to ReadAhead
. (https://www.newtonsoft.com/json/help/html/SerializationSettings.htm#MetadataPropertyHandling)
Thank you for solution. It is working now. Would be nice to have a hint on TypeNameHandling with recommendation for MetadataPropertyHandling because the exception can happens occasionally.
Source/destination types
Source/destination JSON
Actual behavior
Exception: "Could not convert string to decimal: System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.Decimal, System.Private.CoreLib]], System.Private.CoreLib. Path 'Data.$type', line 1, position 231." | string
| Path | "Data.$type" | string
at Newtonsoft.Json.JsonReader.ReadDecimalString(String s) at Newtonsoft.Json.JsonTextReader.FinishReadQuotedNumber(ReadType readType) at Newtonsoft.Json.JsonTextReader.ReadNumberValue(ReadType readType) at Newtonsoft.Json.JsonTextReader.ReadAsDecimal() at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader) at PMOExpress.BL.Tests.MetadataExtensionsTests.Test1() in C:\Projects\Sources\Tests\Data.Tests\ExtensionsTests.cs:line 517
Steps to reproduce
Create a controller, that returns a json:
Navigate to controller in Chrome or IE and save result to a file. Notice that property"$type" is in the last position as browser sorts properties of json object.
Create test and paste context of the file to variable. I already did it for variable str