1

I'm trying to deserialize some json from a 3rd party provider, and occasionally it returns some invalid date field (like -0001-01-01 or something). This causes the process to throw an exception.

Is there a way to tell Json.Net to ignore fields that are invalid?

Thanks

Matt

Matt Whetton
  • 6,616
  • 5
  • 36
  • 57
  • You should probably look at the underlying cause of the invalid data, and repair it if possible first, before trying to work around it. – Der Kommissar Apr 22 '15 at 12:45
  • It looks like this field is set to `DateTime.MinValue`. That's not necessarily "invalid". Since `DateTime` is a value type it can't be null; if you want to allow that, think about making your value type fields `Nullable`. – David Apr 22 '15 at 12:47
  • You can mark a property with [XmlIgnore] attribute if you don't want it serialized – auburg Apr 22 '15 at 12:49
  • @auburg, You probably meant `[JsonIgnore]` – haim770 Apr 22 '15 at 12:50
  • maybe this can help you. This explain how to manage deserialization errors in json.net http://stackoverflow.com/questions/26107656/ignore-parsing-errors-during-json-net-data-parsing – Diego Martelli Apr 22 '15 at 12:51
  • The problem is not with JSON serialization. Even if JSON.Net would ignore it, you'll end up with `default(DateTime)` because `DateTime` is a value-type. Consider using a nullable `DateTime?`. – haim770 Apr 22 '15 at 12:53
  • What part of 'the process' throws an exception? As others have said, you could look into extending your converter. This covers extending Newtonsft: http://michaelcummings.net/mathoms/using-a-custom-jsonconverter-to-fix-bad-json-results/ – jparram Apr 22 '15 at 13:06
  • Lots to answer: I have no control over the source data. The field actually has a minus sign in front of it but I do need to check that properly. I don't want to ignore it except when its invalid. The field I'm mapping to is actually a Nullable DateTime. And finally the DeserializeObject method throws the exception – Matt Whetton Apr 22 '15 at 13:11

3 Answers3

5

To expand on the answer from David, I have used a custom DateTime converter:

public class SafeDateTimeConvertor : DateTimeConverterBase
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        DateTime result;
        if (DateTime.TryParse(reader.Value.ToString(), out result))
            return result;
        return existingValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(((DateTime)value).ToString("yyyy-MM-dd hh:mm:ss"));
    }
}

Which is then applied like this:

var result = JsonConvert.DeserializeObject<TestClass>(json, new SafeDateTimeConvertor());
Matt Whetton
  • 6,616
  • 5
  • 36
  • 57
  • Instead of specifying format explicitly, you can use ((DateTime)value).toString("o") - it corresponds to ISO 8601 format – aluky Feb 20 '18 at 21:22
  • You can also decorate desired attribute with [JsonConverter(typeof(SafeDateTimeConvertor))] (similar to https://stackoverflow.com/questions/40256323/json-net-serialize-datetime-minvalue-as-null) – Martin Brabec May 25 '18 at 12:48
1

JSON.NET has numerous ways to control serialization. You might look at Conditional Property (De)Serialization for example.

There's an entire topic in the online docs on Serializing Dates.

You could write a custom converter; see the documentation for the Newtonsoft.Json.Converters namespace.

David
  • 2,226
  • 32
  • 39
0

It happens, third parties can neglect type safety in their JSON. I recommend you contact them. I had a scenario where a property was either a string array or "false". Json.NET didn't like this so as a temporary hack, I created this custom converter to ignore the deserialization exception:

public class IgnoreDataTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try { return JToken.Load(reader).ToObject(objectType); }
        catch { }
        return objectType.IsValueType ? Activator.CreateInstance(objectType) : null;
    }

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

This "TryConvert" approach is not advised. Use it as a temporary solution after you send your thoughts to the designers of the originating JSON you are consuming.

nullable
  • 2,513
  • 1
  • 29
  • 32