【问题标题】:In C#.NET, how do I deserialize a JSON object that is not an array of objects, and has a unique name for every object? [duplicate]在 C#.NET 中,如何反序列化不是对象数组且每个对象都有唯一名称的 JSON 对象? [复制]
【发布时间】:2022-01-12 12:49:24
【问题描述】:

我有一个如下所示的 JSON 对象:

{
  "preface": {
    "title": "Preface",
    "content": [
    ],
    "navigation": [
      {
        "text": "Table of Contents",
        "section": "table-of-contents"
      }
    ]
  },
  "table-of-contents": {
    "title": "The Adventures of Sherlock Holmes",
    "content": [
    ],
    "navigation": [
      {
        "text": "A Scandal in Bohemia",
        "section": "a-scandal-in-bohemia"
      },
      {
        "text": "The Red-Headed League",
        "section": "the-red-headed-league"
      },
      {
        "text": "Return to Preface",
        "section": "preface"
      }
    ]
  },
  "a-scandal-in-bohemia": {
    "title": "A Scandal in Bohemia",
    "content": [
      "Chapter I",
      "Chapter II",
      "Chapter III"
    ],
    "navigation": [
      {
        "text": "Chapter I",
        "section": "bohemia-chapter-1"
      },
      {
        "text": "Chapter II",
        "section": "bohemia-chapter-2"
      },
      {
        "text": "Chapter III",
        "section": "bohemia-chapter-3"
      },
      {
        "text": "Return to Table of Contents",
        "section": "table-of-contents"
      }
    ]
  },
  "bohemia-chapter-1": {
    "title": "Chapter I",
    "content": [
      "To Sherlock Holmes she is always the woman. I have seldom heard him mention her under any other name. In his eyes she eclipses and predominates the whole of her sex. It was not that he felt any emotion akin to love for Irene Adler. All emotions, and that one particularly, were abhorrent to his cold, precise but admirably balanced mind. He was, I take it, the most perfect reasoning and observing machine that the world has seen, but as a lover he would have placed himself in a false position. He never spoke of the softer passions, save with a gibe and a sneer. They were admirable things for the observer--excellent for drawing the veil from men's motives and actions. But for the trained reasoner to admit such intrusions into his own delicate and finely adjusted temperament was to introduce a distracting factor which might throw a doubt upon all his mental results. Grit in a sensitive instrument, or a crack in one of his own high-power lenses, would not be more disturbing than a strong emotion in a nature such as his. And yet there was but one woman to him, and that woman was the late Irene Adler, of dubious and questionable memory.",
      "..."
    ],
    "navigation": [
      {
        "text": "Chapter II",
        "section": "bohemia-chapter-2"
      }
    ]
  },
...
}

如您所见,它不是一个对象数组,每个文档都有一个唯一的名称但结构相同。我想知道如何将其反序列化为 C# 对象列表。这是我到目前为止所拥有的。我的模型:

public class Document
{ 
    public Dictionary<string, Section> Section { get; set; }

    public override string ToString() => JsonSerializer.Serialize<Document>(this);
}

public class Section
{
    public string Title { get; set; }
    public List<string> Content { get; set; }

    [JsonPropertyName("navigation")]
    public List<Navigation> Navigations { get; set; }

    public override string ToString() => JsonSerializer.Serialize<Section>(this);
}

以上是我如何序列化 json 文本文件。我想将其反序列化为要在 Razor 视图上显示的对象列表。这是我的服务方法:

public IEnumerable<Document> GetDocuments()
{
    using (var jsonFileReader = File.OpenText(JsonFileName))
    {
        return JsonSerializer.Deserialize<List<Document>>(jsonFileReader.ReadToEnd(),
            new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
    } 
}

我的 Index.html 后面的代码:

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    public JsonFileService DocumentService;
    public IEnumerable<Document> Documents { get; private set; }

    public IndexModel(ILogger<IndexModel> logger, JsonFileService documentService)
    {
        _logger = logger;
        DocumentService = documentService;
    }

    public void OnGet()
    {
        Documents = DocumentService.GetDocuments();
    }
}

最后在我的 Razor 视图中,我只有这个 foreach 循环:

foreach (var document in Model.Documents)
{
    <h3>@document.Section.Title</h3>
}

当我运行程序时,我得到以下错误和堆栈跟踪:

JsonException: The JSON value could not be converted to System.Collections.Generic.List`1[WebApp.Models.Document]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
System.Text.Json.Serialization.JsonCollectionConverter<TCollection, TElement>.OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out TCollection value)
System.Text.Json.Serialization.JsonConverter<T>.TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T value)
System.Text.Json.Serialization.JsonConverter<T>.ReadCore(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state)
System.Text.Json.JsonSerializer.ReadFromSpan<TValue>(ReadOnlySpan<byte> utf8Json, JsonTypeInfo jsonTypeInfo, Nullable<int> actualByteCount)
System.Text.Json.JsonSerializer.ReadFromSpan<TValue>(ReadOnlySpan<char> json, JsonTypeInfo jsonTypeInfo)
System.Text.Json.JsonSerializer.Deserialize<TValue>(string json, JsonSerializerOptions options)
WebApp.Services.JsonFileService.GetDocuments() in JsonFileService.cs
+    return JsonSerializer.Deserialize<List<Document>>(jsonFileReader.ReadToEnd(),
WebApp.Pages.IndexModel.OnGet() in Index.cshtml.cs
+    Documents = DocumentService.GetDocuments();

我觉得我在这里错过了一个非常简单的步骤。似乎因为 JSON 对象不是对象数组,反序列化器无法将其转换为 IEnumerable。有人可以指导我如何将此 JSON 转换为 C# 对象列表吗?

【问题讨论】:

标签: c# asp.net json .net


【解决方案1】:

您的 JSON 是您为 Section 定义的值的形状

public Dictionary<string, Section> Section { get; set; }

即,它是Dictionary&lt;string,Section&gt;。您不能将其反序列化为其中的List。您必须将其反序列化为该类型

public Dictionary<string,Section> GetDocuments()
{
    using (var jsonFileReader = File.OpenText(JsonFileName))
    {
        return JsonSerializer.Deserialize<Dictionary<string,Section>>(jsonFileReader.ReadToEnd(),
            new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
    } 
}

现场示例:https://dotnetfiddle.net/iUGsR7

【讨论】:

  • 感谢您理解这个问题。我知道这是某个地方的逻辑错误。我以错误的方式查看 JSON 结构,并没有在我的模型中正确定义它。我不再收到错误消息。谢谢!
【解决方案2】:

似乎因为 JSON 对象不是对象数组,反序列化器无法将其转换为 IEnumerable

是的,它不是一个对象数组,它是一个包含其他对象的对象,我相信使用默认的序列化器/反序列化器你将无法处理这个 JSON。

除非您最终使用动态对象(可以是 JObject)然后将其转换为另一个结构,否则唯一的方法是为此特定情况编写自定义序列化程序并构建此 JSON 的解决方法。

你可以试试这个:

var obj = JsonConvert.DeserializeObject<JObject>(json);
var childrenObjects = obj.Children();

这将为您提供此 JSON 上的四个元素的列表,然后您可以将其转换为适当的对象并使用它。

【讨论】:

  • 我相信使用默认的序列化器/反序列化器你将无法处理这个 JSON ...你认为是错误的 ...类似的问题被一次又一次地问到...解决方案是associative array,在C#的情况下是...好吧,它是用重复写的
  • @Selvin 如果您认为已经提供了这个问题的答案,请您链接相关的 Stackoverflow 问题吗?或者也许提供答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 2021-02-11
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多