【问题标题】:How to deserialize multiple json in C#?如何在 C# 中反序列化多个 json?
【发布时间】:2019-08-13 13:08:41
【问题描述】:

我正在通过多个 json 字符串将一些信息加载到我的 Xamarin 应用程序中。当我运行应用程序时,它给了我这个错误:

Newtonsoft.Json.JsonSerializationException: '无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型 'System.Collections.Generic.List`1[APIPost]' 因为该类型需要 JSON数组(例如 [1,2,3])以正确反序列化。 要修复此错误,要么将 JSON 更改为 JSON 数组(例如 [1,2,3]),要么将反序列化类型更改为普通的 .NET 类型(例如,不是像整数这样的原始类型,而不是像这样的集合类型数组或列表 可以从 JSON 对象反序列化。 JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。 路径“postid”,第 1 行,位置 9。'

获取 json 的代码:

HttpClient client = new HttpClient();
var result = await client.GetStringAsync($"{APIConfig.Uri}/post/getPost/{APIConfig.Token}/{User.ID}/{User.Token}");
List<APIPost> response = JsonConvert.DeserializeObject<List<APIPost>>(result);

foreach (APIPost post in response)
{  //Code  }

类 APIPost:

class APIPost
{
    public string state { get; set; }
    public string postid { get; set; }
    public string userid { get; set; }
    public string image { get; set; }
    public string captation { get; set; }
    public string location { get; set; }
    public string date { get; set; }
    public string likes { get; set; }
}

这是我得到的 json:

{
    "postid": "2",
    "userid": "2",
    "image": "asdasdasd",
    "captation": "asdasd",
    "location": null,
    "date": "2019-07-29 20:24:28",
    "likes": "4"
}{
    "postid": "1",
    "userid": "2",
    "image": "susfdfjsadv",
    "captation": "This is just a test.",
    "location": null,
    "date": "2019-07-29 19:58:04",
    "likes": "2"
}

【问题讨论】:

  • 那个 JSON 无效。
  • 为了防止任何进一步的问题,不,你不能哄 json.net 反序列化它,因为它不是有效的 json。如果将这个返回给你的服务器我们说应用程序/json,那么这是后端中的一个错误,因为这不是 JSON。它可能看起来像 JSON,但实际上并非如此。
  • 此外,在上述情况下,尝试进行一些字符串替换以在正确的位置添加逗号,整个内容周围有一些括号,这可能很简单,但这只是一个定时炸弹你会得到一个带有“这只是一个{secret}{not-so-secret}测试”标题[原文如此]的项目,它也会改变数据。或者有人在两个看似 json 的对象之间添加了一个换行符,并且您的字符串替换不再起作用。修复后端,其他一切都是 hack 和等待发生的错误。
  • 我不会将其作为答案发布,因为这里唯一的 正确 答案是后端错误,修复后端,但我确实设法coax Json.net into deserializing it,一点一点。 这不是答案,你不应该使用它,修复后端,你仍然没有有效的 JSON。

标签: c# json xamarin.android


【解决方案1】:

问题不在于 C# 或您使用的 JSON 序列化库。您从服务器接收到的 JSON无效。因此,不能期望任何标准的 JSON 解析库能够成功解析它。您需要自己编写,或者更正 JSON 以使其有效。

一个有效的对象应该是这样的:

{
  "postid": "2",
  "userid": "2",
  "image": "asdasdasd",
  "captation": "asdasd",
  "location": null,
  "date": "2019-07-29 20:24:28",
  "likes": "4"
}

一个有效的对象数组看起来像:

[
  {
    "postid": "2",
    "userid": "2",
    "image": "asdasdasd",
    "captation": "asdasd",
    "location": null,
    "date": "2019-07-29 20:24:28",
    "likes": "4"
  },
  {
    "postid": "1",
    "userid": "2",
    "image": "susfdfjsadv",
    "captation": "This is just a test.",
    "location": null,
    "date": "2019-07-29 19:58:04",
    "likes": "2"
  }
]

在同一个结构中没有“多个 JSON”这样的东西。你要么有一个有效的结构,要么你没有。你当然可以有多个结构,但你不能把它们全部混合成一个这样的结构。

简而言之...修复服务器端代码以发送有效响应。

【讨论】:

    【解决方案2】:

    你对那个 json 的来源有任何控制吗? 您需要提供以下内容:

    [
        {...},
        {...}
    ]
    

    你会没事的

    【讨论】:

      【解决方案3】:

      正如@lasse-v-karlsen 在评论中所说,服务器应该是固定的,但有一种方法可以使用 Newtonsoft.Json 解析它(如果我们处于其中一种 JSON 流场景中):

      using (var file = new StreamReader(@"D:\Temp\test.json", Encoding.UTF8))
      using (var reader = new Newtonsoft.Json.JsonTextReader(file))
      {
          reader.SupportMultipleContent = true;
      
          var serializer = JsonSerializer.CreateDefault();
          
          serializer.Deserialize(reader).Dump();
          while (reader.Read())
              serializer.Deserialize(reader).Dump();
      }
      

      如果您不喜欢将依赖项添加到 json.net,那么我制作了一个非常简单的 JSON 拆分器:

      IEnumerable<string> SplitJsonStream(string jsonString)
      {
          IEnumerable<string> splitJsonStreamInner(char? head, string tail, uint braceNestingLevel, bool insideSubString, string acc)
          {
              if (!head.HasValue)
              {
                  if (braceNestingLevel != 0)
                      throw new ArgumentException("jsonString seems to be invaid");
                  yield break;
              }
          
              char? newHead = null;
              string newAcc = null;
              if (!String.IsNullOrEmpty(tail))
              {
                  newHead = tail.First();
              }
              if (head.HasValue)
              {
                  newAcc = acc + head.Value;
              }
              var newTail = newHead == null ? null : tail.Substring(1);
      
              if (!insideSubString && head == '"') {
                  foreach(var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, true, newAcc))
                      yield return subAcc;
                  yield break;
              }
              if (insideSubString)
              {
                  if (head == '"')
                  {
                      foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, false, newAcc))
                          yield return subAcc;
                      yield break;
                  }
                  foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, insideSubString, newAcc))
                      yield return subAcc;
                  yield break;
              }
      
              if (head == '{')
              {
                  foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel + 1, insideSubString, newAcc))
                      yield return subAcc;
                  yield break;
              }
              else if (head == '}')
              {
                  if (braceNestingLevel == 0)
                      throw new ArgumentException("jsonString seems to be invalid");
                  var newNestingLevel = braceNestingLevel - 1;
                  if (newNestingLevel == 0) {
                      yield return newAcc;
                      newAcc = String.Empty;
                  }
                  foreach (var subAcc in splitJsonStreamInner(newHead, newTail, newNestingLevel, insideSubString, newAcc))
                      yield return subAcc;
                  yield break;
              }
              else
              {
                  foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, insideSubString, newAcc))
                      yield return subAcc;
                  yield break;
              }
          }
      
          jsonString = jsonString.Trim();
          if (jsonString == string.Empty)
              yield break;
          if (!jsonString.StartsWith("{"))
              throw new ArgumentException("jsonString should start with {");
          if (!jsonString.EndsWith("}"))
              throw new ArgumentException("jsonString should end with }");
      
          foreach (var sub in splitJsonStreamInner(jsonString.First(), jsonString.Substring(1), 0, false, String.Empty))
              yield return sub;
      }
      

      以上工作的证明是这个单元测试:

      [Fact()]
      public void JsonSplitterTests()
      {
          Assert.Empty(SplitJsonStream(String.Empty));
      
          Assert.Throws<ArgumentException>(() => SplitJsonStream("x").Count()); // not startswith {
          Assert.Throws<ArgumentException>(() => SplitJsonStream("{x").Count()); // not endswith }
      
          var fooJson = "{ \"foo\": 1 }";
          var splitted = SplitJsonStream(fooJson);
          Assert.Equal(1, splitted.Count());
          Assert.Equal(fooJson, splitted.ElementAt(0));
      
          var barJson = "{ \"bar\": 2 }";
          splitted = SplitJsonStream(fooJson + barJson);
          Assert.Equal(2, splitted.Count());
          Assert.Equal(fooJson, splitted.ElementAt(0));
          Assert.Equal(barJson, splitted.ElementAt(1));
      
          var bazJson = "{ \"baz\": 3 }";
          splitted = SplitJsonStream(fooJson + barJson + bazJson);
          Assert.Equal(3, splitted.Count());
          Assert.Equal(fooJson, splitted.ElementAt(0));
          Assert.Equal(barJson, splitted.ElementAt(1));
          Assert.Equal(bazJson, splitted.ElementAt(2));
      
          // ends with bad nesting level
          Assert.Throws<ArgumentException>(() => SplitJsonStream("{{x}").Count());
          Assert.Throws<ArgumentException>(() => SplitJsonStream("{x}}").Count());
      
          // edge case
          Assert.Equal(1, SplitJsonStream("{ \"foo\": \"{\" }").Count());
      
          //whitespace in front
          Assert.Equal(2, SplitJsonStream("\n{ \"foo\": 1 }{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream("\r\n{ \"foo\": 1 }{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream("\t{ \"foo\": 1 }{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream(" { \"foo\": 1 }{ \"bar\": 2 }").Count());
          //whitespace at the end
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\n").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\r\n").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\t").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 } ").Count());
          //whitespace in the middle
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\n{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\r\n{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\t{ \"bar\": 2 }").Count());
          Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 } { \"bar\": 2 }").Count());
      }
      

      【讨论】:

        猜你喜欢
        • 2015-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-11
        相关资源
        最近更新 更多