当前位置: 首页 > 知识库问答 >
问题:

反序列化DateTime值时发生JSON.NET异常

秦飞航
2023-03-14

我反映了JSON.NET JavaScriptDateTimeConverter类代码,复制了它,并将该类重命名为3DateTimeConverter,以便修改它以更精确和强类型的庄园格式化DateTime对象。

我让它根据JSON.NET输出强类型对象的方式输出一个类型,如:{“$type”:“system.datetime,mscorlib”,“ticks”:0}

运行JsonConverter的重写WriteJson方法来生成该值。

但是,当我尝试使用与相同转换器完全相同的设置反序列化字符串时,重写的ReadJson方法永远没有机会运行并从ticks属性构造DateTime,因为会出现以下错误:

无法将当前JSON对象(例如{“name”:“value”})反序列化为类型“System.DateTime”,因为该类型需要一个JSON基元值(例如string、number、boolean或null)才能正确反序列化.

要修复此错误,可以将JSON更改为JSON基元值(例如,string、number、boolean、null),或者更改反序列化类型,使其成为可以从JSON对象反序列化的普通.NET类型(例如,不是像integer这样的基元类型,不是像数组或列表这样的集合类型)。还可以将JsonObjectAttribute添加到类型中,以强制它从JSON对象反序列化。

路径“滴答”,第1行,位置45。

这是否是某种bug或限制,它将不允许我恢复一个DateTime类型,因为它是一个value-type?还是我错过了什么?

下面是序列化设置:

    JsonSerializerSettings settings = new JsonSerializerSettings();
    settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
    settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
    settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
    settings.ConstructorHandling = ConstructorHandling.Default;
    settings.TypeNameHandling = TypeNameHandling.All;
    settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
    settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
    settings.DateParseHandling = DateParseHandling.DateTime;
    settings.Converters.Add( new AS3DateTimeConverter() );
    //settings.Binder = new AS3SerializationBinder();
    string s = JsonConvert.SerializeObject( new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ), settings );
    object o = JsonConvert.DeserializeObject( s, settings ); //s = "{\"$type\":\"System.DateTime, mscorlib\",\"ticks\":0}" //ERROR OCCURS HERE

共有1个答案

仲孙思源
2023-03-14

问题似乎与反序列化一个裸露的日期有关。当日期包装在另一个对象中时,它似乎起作用。这段代码适用于我:

public class Program
{
    public static void Main(string[] args)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
        settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
        settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
        settings.ConstructorHandling = ConstructorHandling.Default;
        settings.TypeNameHandling = TypeNameHandling.All;
        settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
        settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        settings.DateParseHandling = DateParseHandling.DateTime;
        settings.Converters.Add(new AS3DateTimeConverter());

        TestObject obj = new TestObject { Date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) };
        string s = JsonConvert.SerializeObject(obj, settings);
        Console.WriteLine(s);
        object o = JsonConvert.DeserializeObject(s, settings);
        Console.WriteLine(((TestObject)o).Date.ToString());
    }
}

public class TestObject
{
    public DateTime Date { get; set; }
}

public class AS3DateTimeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JObject jo = new JObject();
        jo.Add("$type", "System.DateTime, mscorlib");
        jo.Add("ticks", ((DateTime)value).Ticks);
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        return new DateTime(jo["ticks"].Value<long>());
    }
}

输出:

{"$id":"1","$type":"Q20224027.TestObject, JsonTest","Date":{"$type":"System.DateTime, mscorlib","ticks":621355968000000000}}
1/1/1970 12:00:00 AM

更新

为了测试是否为带有嵌入类型信息的自定义顶级对象调用转换器的理论,我为date wrapper对象创建了一个转换器,并将其序列化。这起作用了,但前提是我使用deserializeObject 而不是deserializeObject给出提示。代码如下:

namespace Q20224027
{
    public class Program
    {
        public static void Main(string[] args)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
            settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
            settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
            settings.ConstructorHandling = ConstructorHandling.Default;
            settings.TypeNameHandling = TypeNameHandling.All;
            settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
            settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
            settings.DateParseHandling = DateParseHandling.DateTime;
            settings.Converters.Add(new DateWrapperConverter());

            DateWrapper obj = new DateWrapper { Date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) };
            string s = JsonConvert.SerializeObject(obj, settings);
            Console.WriteLine(s);
            object o = JsonConvert.DeserializeObject<DateWrapper>(s, settings);
            Console.WriteLine(((DateWrapper)o).Date.ToString());
        }
    }

    public class DateWrapper
    {
        public DateTime Date { get; set; }
    }

    public class DateWrapperConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(DateWrapper);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            DateWrapper obj = (DateWrapper)value;
            JObject jo = new JObject();
            jo.Add("$type", typeof(DateWrapper).AssemblyQualifiedName);
            jo.Add("ticks", obj.Date.Ticks);
            jo.WriteTo(writer);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
            return new DateWrapper { Date = new DateTime(jo["ticks"].Value<long>()) };
        }
    }
}

输出:

{"$type":"Q20224027.DateWrapper, JsonTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","ticks":621355968000000000}
1/1/1970 12:00:00 AM
 类似资料:
  • 我正在尝试反序列化以下JSON: 通过此方法调用: 方法: 不幸的是,我得到了以下错误: System.Text.Json.JsonException:'JSON 值无法转换为 System.DateTime。路径:$。出版|行号: 0 |BytePositionInLine: 353.' JSON 来自对以下 API 方法的调用: 是正常的 属性 我做错了什么?如何将JSON的<code>pub

  • 问题内容: 将对象反序列化为()时,嵌套对象反序列化为s。是否可以强制将嵌套对象反序列化为s? 问题答案: 我找到了一种通过提供实现将所有嵌套对象转换为的方法: 文档: Json.NET的CustomCreationConverter

  • 问题内容: 我正在反序列化使用的对象,该对象包含Guid类型的私有字段和该字段的公共属性。当我的json中的my的值为null时,我想分配给我的字段。 但是想要访问私有字段,导致在尝试反序列化时出现此错误: 将值{null}转换为类型’System.Guid’时出错。路径“ [0]。属性”,第6行,位置26。 如何使其忽略私有字段,而使用公共属性? 问题答案: Json.NET拒绝为a 设置值,因

  • 我已经开始将一个项目从使用Java标准日期迁移到Joda DateTime。 我的项目使用XML序列化将对象保存到XML文件中。在这个特殊的例子中,我有一个Item类,它有一个DateTime属性。 在某个时候,我正在初始化对象,包括像这样的DateTime属性: 我使用XMLEncoder使用辅助类序列化项目: 显然,日期时间被保存在xml中。。。但毫无价值: 显然,它没有保存任何东西,但不,它

  • 问题内容: 我正在尝试对a进行序列化/反序列化,如果对象是简单类型,这似乎很好,但是当对象更复杂时,它不起作用。 我有这个课: 在我的字典中,我添加了一个带有“重定向链”键的键和一些带有“状态”,“网址”,“父网址”键的简单字符串。我从JSON.Net返回的字符串如下所示: 我用来序列化的代码如下: 反序列化我正在做的事情: 字典恢复正常,所有字符串恢复正常,但是列表未正确反序列化。它只是作为 当

  • 问题内容: 我试图读取JSON文件并将其转换为数组,但是在读取JSON文件后从数组获取空值。我正在为我的班级使用默认构造函数。 JSON文件: 本类: 问题答案: 您的Gson映射与给定的JSON不匹配。默认情况下,Gson通过 确切 名称将JSON属性映射到目标映射中的相应字段。看一眼: 和 属性名称大小写和字段名称大小写不匹配。您需要的是正确映射JSON。要么: 或通过覆盖名称匹配(这更适合J