We've got some JSON that we are deserializing into a strongly-typed object graph in C#. However, we've got one issue: sometimes there is an "empty" value in the JSON (e.g., empty string) in a property that maps to a boolean value in our model.
In our case, we know that 100% of the time, we can translate these "blank" values to Boolean false
.
However, the JSON deserializers I've tried don't know about this (understandably).
I've been trying to find a way to intercept the deserialization of each property, and optionally override the output. I.e., if there was an "interceptor" method I could register, that 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;
}
That's just hypothetical, of course, but hopefully it gives you an idea of what I'm trying to accomplish.
In my research I have not been able to figure out a way to do this. I've 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 haven't been able to figure it out.
Edit: I think you might be able to use the JsonConverterAttribute, but so far I have not been able to get that working.
Writing a custom JsonConverter
for a primitive type is pretty straghtforward:
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 deserialization of all boolean values. If you need this only for specific members, you need to apply JsonConverterAttribute
.
There is an error in the example above. Instead of
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
there should be
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value);
}
otherwise you will get StackOverflow
exception! Strangely why nobody hasn't written about it yet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With