The following example illustrates a fundamental flaw in Json.NET's type handling:
List<object> items = new List<object>() {Guid.NewGuid(),DateTime.Now};
var settings = new JsonSerializerSettings() { TypeNameHandling=TypeNameHandling.All };
var json = JsonConvert.SerializeObject<List<object>>(value,settings);
resulting in the following JSON:
{"$type":"System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib","$values":["9d7aa4d3-a340-4cee-baa8-6af0582b8acd","2014-07-28T21:03:17.1287029-04:00"]}
As you can see the list items have lost their type information. Deserializing that same JSON will result in a list containing just strings.
This issue was previously reported on codeplex and perfunctorily closed, stating including the type information would make the JSON too messy. I am surprised we aren't given a separate option to include primitive type information for such scenarios as the round-trip consistency is broken.
https://json.codeplex.com/workitem/23833
I would expect the data to come back with the same type information that it left with. Does anybody have any suggestions or workarounds to remedy this undesired behavior?
Thanks,
Chris
Here is a solution using a custom JsonConverter
:
public sealed class PrimitiveJsonConverter : JsonConverter
{
public PrimitiveJsonConverter()
{
}
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanConvert(Type objectType)
{
return objectType.IsPrimitive;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch (serializer.TypeNameHandling)
{
case TypeNameHandling.All:
writer.WriteStartObject();
writer.WritePropertyName("$type", false);
switch (serializer.TypeNameAssemblyFormat)
{
case FormatterAssemblyStyle.Full:
writer.WriteValue(value.GetType().AssemblyQualifiedName);
break;
default:
writer.WriteValue(value.GetType().FullName);
break;
}
writer.WritePropertyName("$value", false);
writer.WriteValue(value);
writer.WriteEndObject();
break;
default:
writer.WriteValue(value);
break;
}
}
}
Here is how to use it:
JsonSerializerSettings settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
};
settings.Converters.Insert(0, new PrimitiveJsonConverter());
return JsonConvert.SerializeObject(myDotNetObject, settings);
I'm currently using this solution to serialize an IDictionary<string, object>
instance that can contain primitives.
Hacked this together and tested it out. Obviously this needs unit testing and is more a proof of concept. If you want a dirty solution to get you going this should get one started.
https://github.com/xstos/Newtonsoft.Json/commit/8d3507cbba78f7096a82e42973e56d69c9541c42
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With