How to prevent a single object property from being converted to a DateTime when it is a string

What one can do is to add a custom JsonConverter to the InputModel type to temporarily toggle JsonReader.DateParseHandling to None:

[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
class InputModel
{
    public string Name { get; set; }
    public object Value { get; set; }
}

public class DateParseHandlingConverter : JsonConverter
{
    readonly DateParseHandling dateParseHandling;

    public DateParseHandlingConverter(DateParseHandling dateParseHandling)
    {
        this.dateParseHandling = dateParseHandling;
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var old = reader.DateParseHandling;
        try
        {
            reader.DateParseHandling = dateParseHandling;
            existingValue = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
            serializer.Populate(reader, existingValue);
            return existingValue;
        }
        finally
        {
            reader.DateParseHandling = old;
        }
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Note that, if the JSON to be deserialized contains nested arrays or objects, all recursively contained values will be parsed with DateParseHandling.None.

One might ask, why not add a converter directly to the property, like so?

class InputModel
{
    public string Name { get; set; }
    [JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
    public object Value { get; set; }
}

It turns out that this does not work because, at the time JsonConverter.ReadJson() is called, the reader has already advanced to the date string and tokenized it as a DateTime. Thus the converter must be applied to the containing type.

Leave a Comment