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

当尝试反序列化Json到对象时,获取此异常“Newtonsoft. Json. JsonSerializationException”

全鸿晖
2023-03-14

作为我为Android开发的Xamarin Forms应用程序的一部分,我有一个Json配置文件,其中保存了一些设置,比如该应用程序是否处于调试模式,或者用户登录网站等。

然而,试图从Json文件获取此用户对象会引发上述异常,下面也可以看到完整的异常。

EXCEPTION   10-02-2020 14:06:08  Newtonsoft.Json.JsonSerializationException => Error converting value "{
  "$type": "Dental.App.Models.User, Dental.App",
  "username": "Ole",
  "password": "ole",
  "verifiedStatus": false,
  "creationTime": "10-02-2020 13:35:13"
}" to type 'Dental.App.Models.User'. Path 'User', line 5, position 197.; Stacktrace =>   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType (Newtonsoft.Json.JsonReader reader, System.Object value, System.Globalization.CultureInfo culture, Newtonsoft.Json.Serialization.JsonContract contract, System.Type targetType) [0x000bd] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x000d7] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue (Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.JsonConverter propertyConverter, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.JsonReader reader, System.Object target) [0x00061] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject (System.Object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.String id) [0x00267] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00154] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x0006d] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x000d9] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00053] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.JsonSerializer.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00000] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) [0x0002d] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <f393073e86a643d9809b1a5d0c498495>:0 
  at Wolf.Utility.Main.Transport.JsonManipulator.ReadValueViaModel[T,U] (System.String path, System.String propertyName) [0x000c8] in <46eeb80ce9a440109e5bc07b0f1af244>:0 
  at Dental.App.Config.get_User () [0x00013] in <c94e9f8f60b14ec69bd9794bdf834717>:0 
  at Dental.App.Views.DentalWebPage.DentalWebView_LoadFinished (System.Object sender, System.EventArgs e) [0x00035] in <c94e9f8f60b14ec69bd9794bdf834717>:0 

我试图反序列化的User和ConfigModel对象非常简单。它们可以在下面看到,以及我的Config文件的一部分,其中包含我存储在Json中的一些属性,然后是我的Json。

public class User
    {
        [JsonProperty("username")]
        public string Username { get; set; }
        [JsonProperty("password")]
        public string Password { get; set; }
        [JsonProperty("verifiedStatus")]
        public bool VerifiedStatus { get; set; }
        [JsonProperty("creationTime")]
        public string CreationTime { get; private set; }

        [JsonIgnore]
        public DateTime TimeOfCreation => Convert.ToDateTime(CreationTime);

        public User()
        {
            CreationTime = DateTime.Now.ToString(CultureInfo.CurrentCulture);
        }

        [JsonConstructor]
        public User(string creationTime)
        {
            CreationTime = creationTime;
        }
    }
public class ConfigModel
    {
        public User User { get; set; }
    }
public class Config
    {
        private static User user = new User();
        public static User User
        {
            get => CanSave ? JsonManipulator.ReadValueViaModel<User, ConfigModel>(ConfigPath, nameof(User)) : user;
            set
            {
                if (CanSave) JsonManipulator.WriteValue(ConfigPath, nameof(User), value);
                else user = value;
            }
        }

        private static bool debugMode = true;
        public static bool DebugMode
        {
            get => CanSave ? JsonManipulator.ReadValue<bool>(ConfigPath, nameof(DebugMode)) : debugMode;
            set
            {
                if (CanSave) JsonManipulator.WriteValue(ConfigPath, nameof(DebugMode), value);
                else debugMode = value;
            }
        }       
...
}

{
  "DebugMode": "true",
  "UseCustomOptions": "false",
  "CustomFormats": "{\n  \"$type\": \"System.Collections.Generic.List`1[[ZXing.BarcodeFormat, zxing.portable]], mscorlib\",\n  \"$values\": []\n}",
  "User": "{\n  \"$type\": \"Dental.App.Models.User, Dental.App\",\n  \"username\": \"Ole\",\n  \"password\": \"ole\",\n  \"verifiedStatus\": false,\n  \"creationTime\": \"10-02-2020 13:35:13\"\n}",
  "SelectedMenu": "3"
}

对于这个过程,我的代码中完成工作的部分来自我的实用程序库。此库是我的github上的一个子模块,可以在以下位置找到完整的库:https://github.com/andr9528/Wolf.Utility.Main

下面是我的JsonManipulator类中的方法,该类在尝试反序列化到User对象时抛出所提到的异常,即T是User。有关完整课程,请访问上面的链接。

public class JsonManipulator
    {
        /// <summary>
        /// Parses Json file, and returns the attribute specified by 'propertyName'.
        /// </summary>
        /// <typeparam name="T">The type returned, from the property named after the input 'propertyName'.</typeparam>
        /// <param name="path">Path of the Json file.</param>
        /// <param name="propertyName">Name of the property to return.</param>
        /// <returns></returns>
        public static T ReadValue<T>(string path, string propertyName)
        {
            if (!File.Exists(path))
                throw new ArgumentNullException(nameof(path), $@"No file Exist on the specified path => {path}");

            if (path.Split('.').Last().ToLowerInvariant() != "json")
                throw new ArgumentException("The path given did not end in 'json'");

            var json = File.ReadAllText(path);

            try
            {
                var obj = JObject.Parse(json);
                if (obj != null)
                    return obj[propertyName].ToObject<T>();
                throw new OperationFailedException($"Failed to parse Json from the file located at => {path}");

            }
            catch (Exception ex)
            {
                throw;
            }
        }
        /// <summary>
        /// Deserializes Json file into specified model, and returns the property from it by the value specified in 'propertyName'.
        /// </summary>
        /// <typeparam name="T">The type returned, from the property named after the input 'propertyName'.</typeparam>
        /// <typeparam name="U">The model that is deserialized into, and from which the property is taken and returned.</typeparam>
        /// <param name="path">Path of the Json file.</param>
        /// <param name="propertyName">Name of the property to return.</param>
        /// <returns></returns>
        public static T ReadValueViaModel<T, U>(string path, string propertyName)
        {
            if (!File.Exists(path))
                throw new ArgumentNullException(nameof(path), $@"No file Exist on the specified path => {path}");

            if (path.Split('.').Last().ToLowerInvariant() != "json")
                throw new ArgumentException("The path given did not end in 'json'");

            var json = File.ReadAllText(path);

            try
            {
                var obj = JsonConvert.DeserializeObject<U>(json, new JsonSerializerSettings() 
                { 
                    NullValueHandling = NullValueHandling.Ignore, 
                    TypeNameHandling = TypeNameHandling.All
                });

                var prop = obj.GetType().GetProperties().First(x => x.Name == propertyName);

                return (T)prop.GetValue(obj);
            }
            catch (Exception)
            {

                throw;
            }
        }
...
}

只有我的配置中的User属性的Get部分存在此问题,我需要调用它来获取包含用户名和密码的User对象。

为了尝试解决这个问题,我做了一些更改,这些都可以在上面的代码中看到。下面是一些示例(如果不是全部的话)。

>

  • 将JsonProperty规范添加到用户对象的属性中

    在用户对象上添加了JsonConstructor

    已将用户对象的属性“CreationTime”的类型从DateTime更改为string。

    在JsonManipulator中与ConfigModel类一起创建了ReadValueViaModel方法

    我有一种恼人的感觉,我所缺少的只是某个地方的一小段代码或格式,但我根本不知道我在哪里以及缺少了什么才能让它工作。

    可以随时向我提问以清除任何缺失的信息。

    编辑1:更新的Json格式-直接从自动生成的Json文件复制。根据https://jsonlint.com/,它是有效的Json,因此我的WriteValue方法正在创建有效的Json。

  • 共有1个答案

    闾丘山
    2023-03-14

    您这样做似乎是因为您不知道库的某些特性。这是最常用的库之一(Microsoft在大多数基于web的项目类型中默认都包含了它)-请先看看库的功能,然后再疯狂地尝试重新发明它的功能。

    • 如果在JSON中添加了一个不在模型中的新字段,它将被忽略
    • 如果您的模型中有一个JSON中缺少的项,那么将使用其默认值(..)填充该项 值<对于类,代码>null;对于原语,代码>默认值(例如:对于数字,代码>0)。这不是JSON所能做到的。net正在做;这些字段被忽略,这意味着它们包含默认值
    • 如果要使用默认值添加新字段,则支持该字段

    这是之前的堆栈溢出问题:JSON. net缺少属性的默认值

    下面是一个代码示例:

    void Main()
    {
        string testJSON = @"[{""FirstName"":""Michael"",""LastName"":""Jones""},{""FirstName"":""Jon"",""LastName"":""Smith""}]";
        PersonModel[] people = JsonConvert.DeserializeObject<PersonModel[]>(testJSON);
        people.Dump();
    }
    
    public class PersonModel
    {
        public string FirstName { get; set; }
    
        public string LastName { get; set; }
    
        public string GUID { get; set; }
    
        [DefaultValue(100)] //lets be generous when starting our loyalty program!
        [JsonProperty("LoyaltyPoints", DefaultValueHandling = DefaultValueHandling.Populate)]
        public int LoyaltyPoints { get; set; }
    }
    

    下面是垃圾场的屏幕截图:

    更新:

    你还没有给出一个很好的理由来按照你现在的方式做事。与其存储包含字符串化JSON对象的JSON对象,不如存储如下内容:

    {
        "DebugMode": "true",
        "UseCustomOptions": "false",
        "SelectedMenu": "3",
        "CustomFormats": [],
        "User": {
            "username": "Ole",
            "password": "ole",
            "verifiedStatus": "false",
            "creationTime": "10-02-2020 13:35:13"
        }
    }
    

    您的模型应该如下所示(显然我在这里有点猜测,因为您没有发布所有代码):

    public class Config
    {
        public bool DebugMode { get; set; }
        public bool UseCustomOptions { get; set; }
        public int SelectedMenu { get; set; }
        public List<ZXing.BarcodeFormat> CustomFormats { get; set; }
        public User User { get; set; }
    }
    
    public class User 
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public bool VerifiedStatus { get; set; }
        public DateTime CreationTime { get; set; }
    }
    
    void Main()
    {
        //and then you can just ...
        string myJsonString = "...";
        Config config = JsonConvert.DeserializeObject<Config>(myJsonString);
    }
    
     类似资料:
    • 我尝试反序列化一个巨大的API负载。这个有效负载包含的字段比我需要的要多,因此我正在使用。但是,在某些情况下,反序列化会失败,并显示错误消息: 我找到了解决方案,建议使用 我试过这个。但这于事无补。此外,我的结果数据不是一个单一的值数组。它实际上包含两个值——因此解决方案无论如何都不会相加。 以下是反序列化的目标类。 下面是我测试它的单元测试: 这是我想要反序列化的有效负载

    • 为了确保在我的RESTful web服务中来回发送的数据不冗余,每个嵌套对象都只序列化了它的ID(消息的用户只序列化了用户ID,因为客户端和服务器都已经知道用户的所有详细信息)。 序列化工作正常,产生以下效果: 问题:反序列化不会生成仅具有其ID的嵌套对象。生成的反序列化嵌套对象为空。 以下是前面提到的消息和用户对象。序列化“策略”是从此处指定的第三个选项中使用的:如何仅序列化Jackson的子级

    • 我试图获取我的Web请求JSON输出并解析它。这是输出 我为这些结果创建了公共课程 当我尝试反序列化Record类并选择名称时,我从RootObject类获得名称。这是我的密码

    • 问题内容: 我尝试反序列化包含null属性并具有的对象。 我做的事: 但是 :如果扔掉财产-一切正常!我的意思是传递下一个字符串: 问题 :如何避免此异常或保证杰克逊在序列化期间忽略空值? 抛出: 信息: 原因: 原因: 问题答案: 如果您不想序列化值,则可以使用以下设置(序列化期间): 希望这能解决您的问题。 但是反序列化过程中获得的结果对我来说似乎很可疑(理想情况下,杰克逊应该能够处理序列化输

    • 问题内容: 我有一堂课POJO 我有一个像 我正在使用Jackson ObjectMapper进行反序列化。在不创建任何其他父类的情况下如何获得? 如果不可能,是否有可能获得仅包含json字符串的第一个元素的对象,即在这种情况下和? 问题答案: 您首先需要获取数组 打印(带有)

    • 我需要在PlayFramework中从Json创建object。 你们有什么建议吗? 谢谢!!