I need to disable the default special handling of dictionaries and lists in json.net. I don't care about the prettiness of the json, I just need a properly functional serialization/deserialization mechanism. Specifically, the problems with the default behavior are that additional fields are not serialized if the type implements IEnumerable or IDictionary, and that dictionary keys are just ToString'd instead of properly serialized. I am replacing a BinaryFormatter in an infrastructure component which serializes a huge number of legacy objects, so refactoring all those objects to use mechanisms compatible with the default json.net behavior (attributes, typeconverters etc) would be not only a prohibitively huge undertaking, but I don't think it would even be possible in many cases. I've tried using a custom contract resolver like so:
private class ContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (contract is JsonDictionaryContract || contract is JsonArrayContract)
{
if (typeof(ISerializable).IsAssignableFrom(objectType))
contract = CreateISerializableContract(objectType);
else
contract = CreateObjectContract(objectType);
}
return contract;
}
}
I would expect that would effectively change those types back to using the standard object serialization behavior, but when I try to serialize a simple dictionary with this I get this error
System.ArgumentException : Invalid type owner for DynamicMethod.
at System.Reflection.Emit.DynamicMethod.Init(String name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] signature, Type owner, Module m, Boolean skipVisibility, Boolean transparentMethod)
at System.Reflection.Emit.DynamicMethod..ctor(String name, Type returnType, Type[] parameterTypes, Type owner, Boolean skipVisibility)
at Newtonsoft.Json.Utilities.DynamicReflectionDelegateFactory.CreateDynamicMethod(String name, Type returnType, Type[] parameterTypes, Type owner)
at Newtonsoft.Json.Utilities.DynamicReflectionDelegateFactory.CreateParameterizedConstructor(MethodBase method)
at Newtonsoft.Json.Serialization.JsonObjectContract.set_ParametrizedConstructor(ConstructorInfo value)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
I'm not really sure how to go about addressing that :) Is there a better approach I could be taking? Any help is appreciated, Thanks!
Update: I realized in my above code that it did probably does make sense to maintain JsonArrayContract's for actual array types (as opposed to all IEnumerables), as it's not surprising that a JsonObjectContracts wouldn't necessarily be able to serialize a native array, so I changed the contract resolver like so:
if (contract is JsonDictionaryContract || (contract is JsonArrayContract && !objectType.IsArray))
which now produces this error instead, and I'm just as stumped as ever
Newtonsoft.Json.JsonSerializationException : Cannot preserve reference to array or readonly list, or list created from a non-default constructor: System.Collections.Generic.KeyValuePair`2[System.Int32,System.Int32][]. Path '$values', line 1, position 311.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, 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.CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty member)
at Newtonsoft.Json.Serialization.JsonFormatterConverter.Convert(Object value, Type type)
at System.Runtime.Serialization.SerializationInfo.GetValue(String name, Type type)
at System.Collections.Generic.Dictionary`2.OnDeserialization(Object sender)