3

I'm running into issues when I use JsonConvert.DeserializeObject to convert JSON data to a custom class whenever there's a null value for a property expecting a decimal.

I want to implement a custom rule that is used only when I want to -- don't want a global setting. In this particular case, I want null values to become 0 whenever the property is of a decimal type.

How do I accomplish this?

Sam
  • 26,817
  • 58
  • 206
  • 383
  • 2
    `[JsonConverter(typeof(NullToDefaultConverter))]` from [Json.net deserialization null guid case](https://stackoverflow.com/a/31750851) should work, I think. – dbc Aug 16 '18 at 21:11
  • Is the answer to [Json.net deserialization null guid case](https://stackoverflow.com/a/31750851) close enough to mark this as a duplicate, or is something more concrete needed? – dbc Aug 16 '18 at 22:11
  • That example was perfect. I upvoted your comment and accepting the response from @gnud as the answer. Thank you! – Sam Aug 16 '18 at 22:19

1 Answers1

3

You can either use annotations in the type you're deserializing, or specify custom converters/settings when deserializing (instead of globally). The only good way of only handling some decimal properties is to use annotations, I think.

string json = @"{""val"": null}";

public class NoAnnotation {
    public decimal val {get; set;}
}

public class WithAnnotation {
    [JsonConverter(typeof(CustomDecimalNullConverter))]
    public decimal val {get; set;}
}

void Main()
{   
    // Converting a type that specifies the converter
    // with attributes works without additional setup
    JsonConvert.DeserializeObject(json, typeof(WithAnnotation));

    // Converting a POCO doesn't work without some sort of setup,
    // this would throw
    // JsonConvert.DeserializeObject(json, typeof(NoAnnotation));

    // You can specify which extra converters
    // to use for this specific operation.
    // Here, the converter will be used
    // for all decimal properties
    JsonConvert.DeserializeObject(json, typeof(NoAnnotation),
       new CustomDecimalNullConverter());

    // You can also create custom serializer settings.
    // This is a good idea if you need to serialize/deserialize multiple places in your application,
    // now you only have one place to configure additional converters
    var settings = new JsonSerializerSettings();
    settings.Converters.Add(new CustomDecimalNullConverter());
    JsonConvert.DeserializeObject(json, typeof(NoAnnotation), settings);
}

// For completeness: A stupid example converter
class CustomDecimalNullConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(decimal);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return 0m;
        }
        else
        {
            return Convert.ToDecimal(reader.Value);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue((decimal)value);
    }
}
gnud
  • 77,584
  • 5
  • 64
  • 78