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

独自空忆成欢 提交于 2019-11-28 02:20:46

问题


Here is a simplified version of the model I have to work with:

class InputModel
{
    public string Name { get; set; }
    public object Value { get; set; }
}

And the relevant parts of the controller:

class Controller : ApiController
{
    [HttpPut]
    public async Task<IHttpActionResult> Update([FromBody]InputModel model)
    {
        //implementation
    }
}

the Value property of the InputModel class could be of any type, and which type it will be is only known later on, in a piece of legacy code the model is sent to and that i have no control over.

The problem I have occurs with the following json in the request body:

{
    "name": "X",
    "value": "2001-10-17T13:55:11.123"
}

The default behavior is to parse this json so that the Value property gets converted to a DateTime. DateTimes however are handled very differently from strings in the legacy code and data is lost after handling it (for example: the millisecond part is removed when persisting to the database). So when the same value is later requested, the returned value is "2001-10-17T13:55:11" (milliseconds missing).

Of course I can fix this by globally setting this in my web api configuration:

httpConfiguration.Formatters.JsonFormatter.SerializationSettings.DateParseHandling = DateParseHandling.None;

But doing so disables parsing DateTimes also for models in other methods and controllers that have models for which the default behavior is wanted.

What I'm looking for is something like the following (imaginary) code:

class InputModel
{
    public string Name { get; set; }

    [JsonSerializerSettings(DateParseHandling = DateParseHandling.None)]
    public object Value { get; set; }
}

But I can't find out how to achieve this. Any help would be greatly appreciated.


回答1:


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.



来源:https://stackoverflow.com/questions/40632820/how-to-prevent-a-single-object-property-from-being-converted-to-a-datetime-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!