3

I would like the following Author type to have a default JsonConverter, and be able to override it at runtime.

[JsonConverter(typeof(BaseJsonConverter))] public class Author { // The ID of an author entity in the application. public int ID { set; get; } // The ID of an Author entity in its source. public string SourceID { set; set; } } 

I used the following code to override the default converter (i.e., BaseJsonConverter).

public class AlternativeConverter : BaseJsonConverter { // the serializer implementation is removed for clarity. } // Deserialize using AlternativeConverter: var author = JsonConvert.DeserializeObject<Author>(jsonString, new AlternativeConverter()); 

Question

Using the above call, the AlternativeConverter is first constructed; however, then an instance of BaseJsonConverter is initialized and used for deserialization. So, the AlternativeConverter is never used.

Executable example: https://dotnetfiddle.net/l0bgYO


Use case

The application is to convert different JSON objects, obtained from different sources, to a common C# type. Commonly data comes from a source for that we define the default converter (i.e., BaseJsonConverter), and for data coming from other sources, we define different converters per each.


Background

I am aware of methods such as this one, and indeed I am using similar method partially. With ref to that article, I need to have different _propertyMappings depending on the source of input, because in my application attribute to property mapping is not one-to-one. For instance, I have the following JSON objects:

{ "id":123 } // and { "id":"456" } 

where the first JSON object should be deserialized to:

author.ID = 123 author.SourceID = null 

and the second JSON object should be deserialized as:

author.ID = 0 author.SourceID = "456" 
6
  • From what I can see, your json keys are the same. the values are only different. So why don't you try to just parse the json string to a JToken as the C# object that you need? Unless, I don't quite get your question, it seems like you're making your life difficult. Commented Mar 10, 2020 at 23:39
  • Just having a json object is not enough to decide which Json attribute shall be mapped to which property. Hence, it is required to deserialize within the context of the input source, i.e., having different converters for jsons from the different sources. Commented Mar 10, 2020 at 23:44
  • Actually it is. JToken is dynamic. You already have an object named Author. If you know that the incoming json is of type Author, add [JsonProperty("blabla")] on top of each variable and parse it as a JToken and C# will do the rest. Again, if I'm missing the point, do let me know. Commented Mar 10, 2020 at 23:46
  • Thanks for the suggestion, but yes, I guess you're missing the point. If I follow your suggestion (which I am kinda doing now and trying to avoid it), there will be multiple properties with [JsonProperty("blabal")]. For instance, both ID and SourceID will have [JsonProperty("id")], plz see the Json examples. Commented Mar 10, 2020 at 23:49
  • Ah now I see, what you're trying to do. based on the type, you're trying to attach the incoming 'id' of the json to one of the properties in Author. If it's an int, to an int. Got it Commented Mar 10, 2020 at 23:53

2 Answers 2

1

You can use a custom ContractResolver to override a [JsonConverter] attribute programmatically. To solve your problem you could make a custom resolver like this:

public class CustomResolver : DefaultContractResolver { private Dictionary<Type, JsonConverter> Converters { get; set; } public CustomResolver(Dictionary<Type, JsonConverter> converters) { Converters = converters; } protected override JsonObjectContract CreateObjectContract(Type objectType) { JsonObjectContract contract = base.CreateObjectContract(objectType); if (Converters.TryGetValue(objectType, out JsonConverter converter)) { contract.Converter = converter; } return contract; } } 

Then, when you wanted to use the AlternativeConverter in place of the BaseJsonConverter, you could use the custom resolver like this:

// map the `Author` type to the `AlternativeConverter` var converters = new Dictionary<Type, JsonConverter>() { { typeof(Author), new AlternativeConverter() } }; // Create a resolver with the converter mapping and add it to the serializer settings var settings = new JsonSerializerSettings { ContractResolver = new CustomResolver(converters) }; // Use the settings when deserializing var author = JsonConvert.DeserializeObject<Author>(jsonString, settings); 

Demo Fiddle: https://dotnetfiddle.net/cu0igV


Of course, if all you're really doing with these converters is remapping properties to different names, you could just use a ContractResolver for that in the first place and get rid of the converters altogether. See Json.NET deserialize or serialize json string and map properties to different property names defined at runtime for more information on that approach.

Sign up to request clarification or add additional context in comments.

Comments

0

I think you should try to use different JsonSerializerSettings instances for different data sources, with different Converters collections. And remove JsonConverter attributes from your classes.

2 Comments

I cannot remove JsonConvert attribute because it is essential for (de)serialization of default types.
Also, I am trying to use something like Converters, however, the default converter set via the JsonConverter attribute overrides whatever serializer I pass.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.