【问题标题】:How to prevent a single object property from being converted to a DateTime when it is a string如何防止单个对象属性在为字符串时转换为 DateTime
【发布时间】:2017-03-30 16:36:30
【问题描述】:

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

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

以及控制器的相关部分:

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

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

我在请求正文中出现以下 json 的问题:

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

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

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

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

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

我正在寻找类似于以下(虚构)代码的内容:

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

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

但我不知道如何实现这一点。任何帮助将不胜感激。

【问题讨论】:

    标签: c# json asp.net-web-api asp.net-web-api2 deserialization


    【解决方案1】:

    可以做的是在InputModel 类型中添加一个custom JsonConverter,以暂时将JsonReader.DateParseHandling 切换为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

    有人可能会问,为什么不直接将转换器添加到属性中呢?

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多