如何防止单个对象属性在是字符串时转换为 DateTime [英] How to prevent a single object property from being converted to a DateTime when it is a string

查看:14
本文介绍了如何防止单个对象属性在是字符串时转换为 DateTime的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我必须使用的模型的简化版本:

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
    }
}

InputModel 类的 Value 属性可以是任何类型,它是哪种类型只有稍后知道,在模型被发送到的一段遗留代码中,我无法控制.

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.

我遇到的问题是请求正文中的以下 json:

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

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

默认行为是解析此 json,以便将 Value 属性转换为 DateTime.然而,DateTimes 的处理方式与遗留代码中的字符串非常不同,处理后数据会丢失(例如:当持久化到数据库时,毫秒部分被删除).因此,当稍后请求相同的值时,返回的值为2001-10-17T13:55:11"(缺少毫秒).

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).

当然我可以通过在我的 web api 配置中全局设置来解决这个问题:

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

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

但这样做也会禁用解析 DateTimes 的其他方法和控制器中的模型,这些模型具有需要默认行为的模型.

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.

推荐答案

可以做的是添加一个 自定义 JsonConverterInputModel 类型以临时切换 JsonReader.DateParseHandlingNone:

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();
    }
}

请注意,如果要反序列化的 JSON 包含嵌套数组或对象,则所有递归包含的值都将使用 DateParseHandling.None 进行解析.

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; }
}

事实证明这是行不通的,因为当时 JsonConverter.ReadJson() 被调用,阅读器已经前进到日期字符串并将其标记为DateTime. 因此转换器必须应用于包含类型.

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.

这篇关于如何防止单个对象属性在是字符串时转换为 DateTime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆