C # JSON deserialization: is it possible to intercept the deserialization and possibly change the result?

We have JSON that we deserialize into a strongly typed graph of objects in C #. However, we have one problem: sometimes in JSON (for example, an empty string) there is an empty value in the property that maps to a Boolean value in our model.

In our case, we know that in 100% of cases we can translate these "empty" values ​​into Boolean false .

However, the JSON deserializers that I tried about are not aware of this (understandably).

I tried to find a way to intercept deserialization of each property and possibly override the output. Ie, if there was a "interceptor" method that I could register, it looked like this:

  public Boolean JsonDeserializationInterceptor(String rawJson, System.Type targetType, out object result) { Boolean overrodeValue = false; result = null; if(targetType == typeof(System.Boolean)) { overrodeValue = true; // We'll pretend that we're interpreting the string "Yes" as // true, and all other values are false. if (rawJson != null && rawJson.ToLower() == "\"yes\"") result = true; else result = false; } return overrodeValue; } 

This is just hypothetical, of course, but hopefully it gives you an idea of ​​what I'm trying to accomplish.

In my research, I could not find a way to do this. I looked at Json.NET , System.Runtime.Serialization.Json.DataContractJsonSerializer and System.Web.Script.Serialization.JavaScriptSerializer . I bet there is a way to do this, and I just couldn't figure it out.

Change I think you could use JsonConverterAttribute , but so far I have not been able to do this.

+6
source share
2 answers

Writing a custom JsonConverter for a primitive type is quite difficult:

 using System; using Newtonsoft.Json; namespace So16972364JsonDeserializeConverter { class BoolConverter : JsonConverter { public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { switch (reader.TokenType) { case JsonToken.String: if ((string)reader.Value == "") return false; break; case JsonToken.Boolean: return reader.Value; } throw new JsonReaderException("Expected boolean or empty string."); } public override bool CanConvert (Type objectType) { return objectType == typeof(bool); } } class Program { const string json = @" { b1: true, b2: false, b3: '' } "; static void Main () { Foo foo = JsonConvert.DeserializeObject<Foo>(json, new JsonSerializerSettings { Converters = { new BoolConverter() } }); Console.WriteLine(JsonConvert.SerializeObject(foo, Formatting.Indented)); Console.ReadKey(); } } class Foo { public bool b1, b2, b3; } } 

This code overrides the deserialization of all Boolean values. If you need it only for specific members, you need to apply JsonConverterAttribute .

+5
source

There is an error in the above example. Instead

 public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } 

should be

 public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteValue(value); } 

otherwise you will get a StackOverflow exception! It is strange why no one has written about this yet.

0
source

Source: https://habr.com/ru/post/946728/


All Articles