2

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);
            }
        }
    }
}
Community
  • 1
  • 1
bboyle1234
  • 4,859
  • 2
  • 24
  • 29
  • I've also tried using this but it also didn't work: `var json = JsonConvert.SerializeObject(new SomeClass { A = 10 }, new SpecialConverter());` – bboyle1234 Jul 18 '19 at 03:28
  • 1
    Looks like a duplicate of [C# JsonConvert using the default converter instead of the custom converter](https://stackoverflow.com/q/53401189/3744182), agree? Also related: [Why Json.net does not use customized IsoDateTimeConverter?](https://stackoverflow.com/a/41216067/3744182). – dbc Jul 18 '19 at 03:40
  • 1
    Demo of using `ConverterDisablingContractResolver` from [C# JsonConvert using the default converter instead of the custom converter](https://stackoverflow.com/q/53401189/3744182) here: https://dotnetfiddle.net/2TwlCK – dbc Jul 18 '19 at 03:49
  • 1
    Thanks I upvoted your answers on the other questions. – bboyle1234 Jul 18 '19 at 04:04

0 Answers0