反序列化名称中包含日期字符串的字段时出现Json.NET问题



我有一个具有以下属性的对象(自1970年以来,它具有毫秒数):

public double AsOfDate { get; set; }

当我序列化它(在ASP.NETMVC4应用程序中)时,它很好。然而,当我稍后将JSON对象发送回服务器时,我得到了反序列化错误:

读取日期时出错。意外的标记:Integer。路径"performance.asOfDate",第1行,位置95。

和堆栈跟踪:

位于Newtonsoft.Json.JsonReader.ReadAsDateTimeInternal()位于的Newtonsoft.Json.JsonTextReader.ReadAsDateTime()Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReaderreader,JsonContract合约,Boolean hasConverter)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndConstructorValues(JsonObjectContract合约,JsonProperty容器属性,JsonReader阅读器,类型objectType)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectFromNonDefaultConstructor(JsonReader阅读器,JsonObjectContract合同,JsonProperty容器Property,ConstructorInfo ConstructorInfo,字符串id)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReaderreader,JsonObjectContract objectContract,JsonPropertycontainerMember,JsonProperty containerProperty,字符串id,Boolean&createdFromNonDefaultConstructor)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReaderreader,Type objectType,JsonContract合约,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerMember,对象existingValue)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReaderreader,Type objectType,JsonContract合约,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerMember,对象existingValue)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndConstructorValues(JsonObjectContract合约,JsonProperty容器属性,JsonReader阅读器,类型objectType)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectFromNonDefaultConstructor(JsonReader阅读器,JsonObjectContract合同,JsonProperty容器Property,ConstructorInfo ConstructorInfo,字符串id)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReaderreader,JsonObjectContract objectContract,JsonPropertycontainerMember,JsonProperty containerProperty,字符串id,Boolean&createdFromNonDefaultConstructor)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReaderreader,Type objectType,JsonContract合约,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerMember,对象existingValue)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReaderreader,Type objectType,JsonContract合约,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerMember,对象existingValue)Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader阅读器,类型对象类型,布尔检查AdditionalContent)

所以,在反序列化阶段,JSON库试图将asOfDate解析为DateTime,只是因为它的名称中有Date字符串?有办法解决这个问题吗?以下是请求正文示例:

{
   "performance":{
      "performanceSinceInception":0.76,
      "performanceMtd":0.41,
      "asOf":1382486400000,
      "inceptionDate":1359676800000,
      "monthPerformanceStart":1380585600000
   },       
   "rating":1,
   "isActive":false,
   "effectiveFrom":1359676800000,
   "effectiveTo":1383919343000,
   "globalValidationFlag":true,
   "whitelistValidationFlag":false,
   "canBeReactivated":false,
   "canBeRemoved":false,
   "belongsToMainBucket":true
}

我已经测试过了,当我将属性名称从asOfDate更改为asOf时,它就可以工作了。所以我谴责基于约定的反序列化。有没有办法推翻它?

我认为问题在于您的类没有无参数(默认)构造函数。(我可以判断是这种情况,因为在您发布的堆栈跟踪中,它显示CreateObjectFromNonDefaultConstructor正在被调用。)

当一个类没有默认构造函数时,Json.Net会做一些奇怪的事情,试图弄清楚它可以使用哪些构造函数来创建对象,以及如何将构造函数参数与Json数据匹配以调用它。这需要一定的猜测,而且并不总是有效的。

一种特别的情况是,如果您有一个构造函数,其参数名称与JSON数据中的属性匹配,但数据类型不兼容,那么它将无法正常工作。例如,考虑以下程序:

class Program
{
    static void Main(string[] args)
    {
        string json = @"{ ""asOf"" : 1382486400000 }";
        var obj = JsonConvert.DeserializeObject<Performance>(json);
        Console.WriteLine(obj.asOf);
    }
    public class Performance
    {
        public Performance(DateTime asOf)
        {
            this.asOf = asOf.Ticks;
        }
        public double asOf { get; set; }
    }
}

此程序将失败,错误与您的问题相同。没有默认的构造函数,所以Json.Net尝试使用那里的构造函数。构造函数中有一个参数asOf,恰好数据中也有一个属性asOf。所以它试图用它来构造对象。但是,这不会起作用,因为数据是一个整数,Json.Net不知道如何将其转换为日期。

有几种可能的解决方案。最好的解决方案是简单地添加一个默认构造函数。如果有一个公共的默认构造函数,Json.Net总是更喜欢它而不是其他构造函数。通过此更改,Json.Net将使用默认构造函数来创建对象,然后将Json数据中的asOf属性与对象中的asOf属性相匹配,后者的类型兼容。所以这很好用。

另一种可能的解决方案是更改构造函数参数的名称,使其与JSON数据不匹配(或者反过来,更改类和JSON数据中对象属性的名称,使得它们与构造函数不匹配)。在这种情况下,Json.Net被迫使用默认值传递给构造函数来创建对象。然后,它将把JSON数据与任何剩余的对象属性进行匹配。对于我们的例子,这也是有效的。当然,依赖这种行为有点风险,因为Json.Net不知道构造函数中可能有什么逻辑。例如,您可能有一个代码,它拒绝默认值(例如null)对某些参数无效。在这种情况下,Json.Net将无法构造该对象。它只能用你的付出做到最好,而这可能并不总是如预期的那样奏效。

第三种解决方案是为对象创建一个自定义JsonConverter,并让Json.Net使用它来构造和填充对象。如果你有一个复杂的对象,它不能有默认的构造函数,但需要特殊的处理来填充它,这是你最好的选择,而不是依赖Json.Net来尝试自己解决它。当然,这需要更多的代码,但制作转换器并不太难。如果你需要的话,我可以提供一个例子。

相关内容

  • 没有找到相关文章

最新更新