尝试反序列化多维数组时出现 Newtonsoft JSON JsonReaderException

问题描述

我的应用程序中有一个脚本,用于从我的 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","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<DataType>(stringToDeserialize)) 并且能够将其解析为简单列表时,我的应用程序中的另一个脚本也使用 ["SUCCESS","adlhfbaf"] 工作,但在尝试时失败使用上面的多维数组 JSON。

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

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

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

                };

解决方法

而不是反序列化成字典。为您的响应创建一个模型。然后将其反序列化为该模型的列表。你可以在下面看到一个例子。我基于您提供的代码,只是将所有标注替换为一个变量,该变量包含一个 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\",\"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;}
}
,

我的问题

非常感谢所有试图解决我的问题的人。对自己感觉很愚蠢,我现在已经解决了这个问题 xD。非常感谢@Jason,他提到以十六进制查看我的变量内容。我写了几行将变量转换为十六进制,复制此输出并将其放入在线十六进制到 ASCII 转换器中,发现我误读了程序的输出并且忽略了返回的数据量的两倍以上由于在 PHP 中留下了一个恶意 print_r() 命令而导致 PHP 脚本在进行 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","contents":"whwrgthwr","time_stamp":"0-0-0"}]

而不仅仅是:

[{"type":"0","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<string> 而不仅仅是 List<string>