Test on Fiddle: https://dotnetfiddle.net/RyxMjm
using NewtonSoft.Json;
Let SomeClass
be a library class that needs a custom json converter. The library it comes in provides the custom json converter, UsualConverter
, and links the converter to the class by specifying it in the class definition with a JsonConverter
attribute.
[JsonConverter(typeof(UsualConverter))]
class SomeClass {
public int A;
}
class UsualConverter : JsonConverter {
public override bool CanConvert(Type objectType)
=> objectType == typeof(SomeClass);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var jObject = JObject.ReadFrom(reader);
return new SomeClass {
A = jObject["A"].ToObject<int>(),
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var jObject = new JObject();
jObject["A"] = ((SomeClass)value).A;
jObject.WriteTo(writer);
}
}
However I now need to implement and use a different json converter for it. So I create my own:
class SpecialConverter : JsonConverter {
public override bool CanConvert(Type objectType)
=> objectType == typeof(SomeClass);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var jObject = JObject.ReadFrom(reader);
return new SomeClass {
A = 100,
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var jObject = new JObject();
jObject["A"] = "SpecialValue";
jObject.WriteTo(writer);
}
}
The problem arises when I simply can't get JsonConvert to use my new converter ... it always uses the original header specified with an attribute in the class definition.
The following code throws the exception. How can I get the serialization/deserialization to be done with my new custom converter?
class Program {
static void Main(string[] args) {
var settings = new JsonSerializerSettings();
settings.Converters.Add(new SpecialConverter());
var json = JsonConvert.SerializeObject(new SomeClass { A = 10 }, settings);
if (!json.Contains("SpecialValue"))
throw new Exception("Wrong converter was used.");
}
}
It is possible for me to edit the library containing the "offending" classes, however, I don't want to break other applications already using the library. Answers that involve modifying the library code will be accepted if they do not break other applications already using the library.
Test on Fiddle: https://dotnetfiddle.net/RyxMjm
Update
Using what I learned from answers on duplicate questions, I created the following extension method to allow application code to quickly apply the alternate JsonConverter to their serializer. It can only break application code in the rare times that the application code has already applied another ContractResolver
to the serializer settings object.
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SomeNameSpace {
public static class SerializerSettingsExtensions {
public static void UseAlternateConverterForSomeClass(this JsonSerializerSettings settings, JsonConverter jsonConverter) {
settings.ContractResolver = ConverterDisablingContractResolver.Instance;
settings.Converters.Add(jsonConverter);
}
private class ConverterDisablingContractResolver : DefaultContractResolver {
public static readonly ConverterDisablingContractResolver Instance = new ConverterDisablingContractResolver();
private ConverterDisablingContractResolver() { }
protected override JsonConverter ResolveContractConverter(Type objectType) {
if (objectType == typeof(SomeClass)) return null;
return base.ResolveContractConverter(objectType);
}
}
}
}