【问题标题】:Newtonsoft JSON JsonReaderException when trying to deserialize multidimensional array尝试反序列化多维数组时出现 Newtonsoft JSON JsonReaderException
【发布时间】:2020-12-21 14:00:33
【问题描述】:

我的应用程序中有一个脚本,它从我的 PHP REST API 收集一些 JSON 数据。 API 使用json_encode() 序列化它生成的多维数组。我的应用程序中的脚本应该将其反序列化为 C# 中的等价物,以便我可以循环遍历它,因为每个子数组都代表数据库中的一“行”信息。但是,我遇到了这个错误:

Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: A. Path '', line 0, position 0.
  at Newtonsoft.Json.JsonTextReader.ParseValue () [0x002b3] in <2073514815234917a5e8f91b0b239405>:0 
  at Newtonsoft.Json.JsonTextReader.Read () [0x0004c] in <2073514815234917a5e8f91b0b239405>:0 
  at Newtonsoft.Json.JsonReader.ReadAndMoveToContent () [0x00000] in <2073514815234917a5e8f91b0b239405>:0 
  at Newtonsoft.Json.JsonReader.ReadForType (Newtonsoft.Json.Serialization.JsonContract contract, System.Boolean hasConverter) [0x0004a] in <2073514815234917a5e8f91b0b239405>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x000db] in <2073514815234917a5e8f91b0b239405>:0 
  at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x

JSON(与我的应用从服务器接收到的完全相同)

[{"type":"0","ID":"1","groupID":"0","authorID":"14","contents":"rfgwgfgdfssd","time_stamp":"0-0-0"}, {"type":"0","ID":"2","groupID":"0","authorID":"14","contents":"whwrgthwr","time_stamp":"0-0-0"}]

脚本

async void getUpdatesAsync()
        {
            Console.WriteLine("starting...");

            BackendConnect connectionHandler = new BackendConnect("vocal/posts/index.php");

            var updatesRequestInfo = new Dictionary<string, string>
            {

                {"sessionID", "c1f7a973c04e18a05342ecc2d16f7339"},
                {"type", "updateFeed"},
                {"userID", "14"}

            };

            connectionHandler.addData(updatesRequestInfo);

            string updatesReturn = await connectionHandler.sendForm(); // returns the json

            Console.WriteLine(updatesReturn); // the above json was copied and pasted from this output

            List<Dictionary<string, string>> updatesArray = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(updatesReturn); // this line causes error

            Console.WriteLine(updatesArray);

            //updatesArray.ForEach(Console.WriteLine);

        }

我的应用程序中的另一个脚本也使用 JsonConvert.DeserializeObject&lt;DataType&gt;(stringToDeserialize) 在将单维数组 (["SUCCESS", "adlhfbaf"]) 提供给反序列化函数并且能够将其解析为简单列表时工作,但在尝试使用多维数组时失败上面的 JSON。

到目前为止,我已尝试将 updatesArray 变量设置为无数种不同的数据类型,以查看这是否是我怀疑的问题,但作为 C# 等语言的新手,您必须预先定义数据类型,我很难解决这个问题。

本质上,我想将它作为 C# 中的字典列表导入,以便我可以使用 foreach() 循环遍历初始列表的每个索引并恢复可以获取特定值(例如内容)的字典.下面是我要导入的示例(我知道语法不正确,但至少是一个粗略的想法)

var updatesArray = new List<Dictionary<string, string>>
                {
                    {
                        {"type", "0"},
                        {"ID", "1"},
                        {"groupID", "0"},
                        {"authorID", "14"},
                        {"contents", "rfgwgfgdfssd"},
                        {"time_stamp", "0-0-0"}
                    },
                    {
                        {"type", "0"},
                        {"ID", "2"},
                        {"groupID", "0"},
                        {"authorID", "14"},
                        {"contents", "whwrgthwr"},
                        {"time_stamp", "0-0-0"}
                    }

                };

【问题讨论】:

  • 你能把你的json解析成一个JObject吗?
  • 嗨,我不熟悉 JObjects,它是如何工作的?
  • 而不是反序列化成字典列表。为您的响应创建一个模型并将其反序列化为该模型的列表。这也将使您对代码中的数据进行智能感知
  • 我已经为您的字符串测试了 JsonConvert.Deserialize&lt;List&lt;Dictionary&lt;string, string&gt;&gt; 并且它有效。您的字符串实际上不同,或者您的 ListDictionary 不是来自 System.Collections.Generic 命名空间。另外,您使用什么 Newtonsoft.Json 版本?
  • JObject.Parse(jsonstring);

标签: c# list dictionary xamarin json.net


【解决方案1】:

而不是反序列化成字典。为您的响应创建一个模型。然后将其反序列化为该模型的列表。您可以在下面看到一个示例。我基于您提供的代码,只是将所有调用替换为一个包含 JSON 字符串的变量,就像您从调用中获得的那样

public static void Main()
{

    {       
        //json string
        //you should fix the timestamp coming back...not a real timestamp
        var testresponse = "[{\"type\":\"0\",\"ID\":\"1\",\"groupID\":\"0\",\"authorID\":\"14\",\"contents\":\"rfgwgfgdfssd\",\"time_stamp\":\"0-0-0\"},{\"type\":\"0\",\"ID\":\"2\",\"groupID\":\"0\",\"authorID\":\"14\",\"contents\":\"whwrgthwr\",\"time_stamp\":\"0-0-0\"}]";

        Console.WriteLine(testresponse);

        var updatesArray = JsonConvert.DeserializeObject<List<TestModel>>(testresponse);

        Console.WriteLine(updatesArray[0].Id);
        Console.WriteLine(updatesArray[1].Id);
        
        var after = JsonConvert.SerializeObject(updatesArray);
        
        Console.WriteLine(after);

    }
}

如果时间戳是 DateTime,请将数据类型设置为 DateTime,但您需要从服务器发送一个真实的 DateTime

public class TestModel
{
    [JsonProperty(PropertyName = "type")]
    public int Type { get; set; }
    [JsonProperty(PropertyName = "ID")]
    public int Id {get; set;}
    [JsonProperty(PropertyName = "groupID")]
    public int GroupId {get; set;}
    [JsonProperty(PropertyName = "authorID")]
    public int AuthorId {get; set;}
    [JsonProperty(PropertyName = "contents")]
    public string Contents {get; set;}
    [JsonProperty(PropertyName = "time_stamp")]
    public string TimeStamp {get; set;}
}

【讨论】:

  • 嗨,我很可能会在我的代码中实现一个自定义模型,所以谢谢!但是我的问题仍然存在,我相信是由反序列化函数的输入引起的。
  • @MatthewSwallow 如果您能够注销从服务器获取的数据,这将很有帮助。您还可以使用在线 JSON 验证器(您必须先使用工具对其进行反序列化;也许可以尝试手动进行)来验证响应实际上是有效的 JSON。您可能必须弄乱您的 JSON 设置才能使其正常工作
  • 感谢您的回复,我现在已经解决了这个问题。我原来的帖子已经包含了你要求的输出(或者当时我认为输出是 xD)
  • @MatthewSwallow 很乐意为您提供帮助,欢迎来到 Stack Overflow。如果此答案解决了您的问题,请将其标记为已接受。
【解决方案2】:

我的问题

非常感谢所有尝试解决我的问题的人。对自己感到很愚蠢,我现在已经解决了这个问题xD。非常感谢@Jason,他提到以十六进制查看我的变量内容。我写了几行来将变量转换为十六进制,复制这个输出并将其放入在线十六进制到 ASCII 转换器中,发现我误读了程序的输出,并且忽略了返回的数据量的两倍以上PHP 脚本由于在测试中遗留在 PHP 中的流氓 print_r() 命令在 JSON 编码之前输出了数组:

Array
(
    [0] => Array
        (
            [type] => 0
            [ID] => 1
            [groupID] => 0
            [authorID] => 14
            [contents] => rfgwgfgdfssd
            [time_stamp] => 0-0-0
        )

    [1] => Array
        (
            [type] => 0
            [ID] => 2
            [groupID] => 0
            [authorID] => 14
            [contents] => whwrgthwr
            [time_stamp] => 0-0-0
        )

)
[{"type":"0","ID":"1","groupID":"0","authorID":"14","contents":"rfgwgfgdfssd","time_stamp":"0-0-0"},{"type":"0","ID":"2","groupID":"0","authorID":"14","contents":"whwrgthwr","time_stamp":"0-0-0"}]

不仅仅是:

[{"type":"0","ID":"1","groupID":"0","authorID":"14","contents":"rfgwgfgdfssd","time_stamp":"0-0-0"},{"type":"0","ID":"2","groupID":"0","authorID":"14","contents":"whwrgthwr","time_stamp":"0-0-0"}]

总结的其他有用的可能问题

为了在未来帮助其他人,我认为公平地说,我从这个线程中学到的一些东西可能是那个错误的问题。

流氓字节顺序标记/零宽度空间

  • 在 C# 中,可以使用 String.Trim() 函数删除此类 Unicode 字符
  • 零宽度空间始终以 unicode 表示为 U+200B
  • 字节顺序标记根据使用的编码而改变。对于 UTF-16,BOM 字符表示为U+FEFF
  • 这意味着这个问题的修复是myString = myString.Trim(new char[]{'\uFEFF','\u200B'});

不正确的数据类型/不确定要使用什么数据类型

  • 创建适合您所需结构的自己的对象(如上面@ejwill 的帖子中所示)
  • 反序列化成这个结构

列表/字典意外从不同的命名空间导入

  • 确保所有导入的模块都没有 List 或 Dictionary 的定义
  • 如果他们这样做,您可以:
  • 缩短您的包含,以便只包含该模块中您需要的对象(即:using System.Text; 而不是using System;
  • 或者将命名空间添加到列表/字典声明的前面(即:System.Collections.Generic.List&lt;string&gt; 而不仅仅是 List&lt;string&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2017-10-16
    • 1970-01-01
    • 2018-04-25
    • 2013-06-06
    相关资源
    最近更新 更多