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

System.Text.Json-将嵌套对象反序列化为字符串

苏高旻
2023-03-14

我正在尝试使用System.Text.Json.JsonSerializer来部分地反序列化模型,因此其中一个属性被读取为包含原始JSON的字符串。

public class SomeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Info { get; set; }
}

示例代码

var json = @"{
                 ""Id"": 1,
                 ""Name"": ""Some Name"",
                 ""Info"": {
                     ""Additional"": ""Fields"",
                     ""Are"": ""Inside""
                 }
             }";

var model = JsonSerializer.Deserialize<SomeModel>(json);

应该生成模型,其中Info属性将原始JSON中的Info对象作为字符串包含:

{
    "Additional": "Fields",
    "Are": "Inside"
}

它不能开箱即用并抛出异常:

System.Text.Json.JsonException:---

到目前为止我尝试了什么:

public class InfoToStringConverter : JsonConverter<string>
{
    public override string Read(
        ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
    {
        return reader.GetString();
    }

    public override void Write(
        Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

并将其应用于模型中

[JsonConverter(typeof(InfoToStringConverter))]
public string Info { get; set; }

并将选项添加JsonSerializer

var options = new JsonSerializerOptions();
options.Converters.Add(new InfoToStringConverter());
var model = JsonSerializer.Deserialize<SomeModel>(json, options);

尽管如此,它还是抛出了相同的异常:

System.Text.Json.JsonException:---

烹饪我需要的东西的正确食谱是什么?它使用Newtonsoft.Json以类似的方式工作。

更新

对我来说,保持嵌套的 JSON 对象尽可能原始是很重要的。因此,我会避免选择反序列化为字典并序列化回来的选项,因为我害怕引入不需要的更改。

共有3个答案

齐志勇
2023-03-14

对已接受答案的快速补充:

如果您还需要编写原始JSON值,以下是转换器的Write方法的实现:

public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
    using (JsonDocument document = JsonDocument.Parse(value))
    {
        document.RootElement.WriteTo(writer);
    }
}

正如github上的dotnet运行时报告所述,这似乎是解决他们决定不实现<code>WriteRawValue

施茂
2023-03-14

您可以为此使用JsonExtensionData属性并声明字典

public class SomeModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonExtensionData]
    public Dictionary<string, JsonElement> ExtensionData { get; set; }

    [JsonIgnore]
    public string Data
    {
        get
        {
            return ExtensionData?["Info"].GetRawText();
        }
    }
}

然后您可以添加一个附加属性以通过Info键从此字典中获取字符串。在Data属性上方的代码中,将包含预期的字符串

{
    "Additional": "Fields",
    "Are": "Inside"
}

由于某些原因,添加具有相同名称 Info 的属性不起作用,即使使用 JsonIgnore 也是如此。有关详细信息,请查看处理溢出 JSON。

您还可以将Info属性声明为JsonElementtype,并从中获取原始文本

public class SomeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public JsonElement Info { get; set; }
}
var model = JsonSerializer.Deserialize<SomeModel>(json);
var rawString = model.Info.GetRawText();

但它会导致模型表示及其序列化的混合。

另一种选择是使用JsonDocument解析数据,枚举属性并逐个解析,如下所示

var document = JsonDocument.Parse(json);
foreach (var token in document.RootElement.EnumerateObject())
{
    if (token.Value.ValueKind == JsonValueKind.Number)
    {
        if(token.Value.TryGetInt32(out int number))
        {
        }
    }
    if (token.Value.ValueKind == JsonValueKind.String)
    {
        var stringValue = token.Value.GetString();
    }
    if (token.Value.ValueKind == JsonValueKind.Object)
    {
        var rawContent = token.Value.GetRawText();
    }
}

孙凌
2023-03-14

找到了正确读取JsonConverter嵌套JSON对象的方法。完整的解决方案如下:

public class SomeModel
{
    public int Id { get; set; }

    public string Name { get; set; }

    [JsonConverter(typeof(InfoToStringConverter))]
    public string Info { get; set; }
}

public class InfoToStringConverter : JsonConverter<string>
{
    public override string Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using (var jsonDoc = JsonDocument.ParseValue(ref reader))
        {
            return jsonDoc.RootElement.GetRawText();
        }
    }

    public override void Write(
        Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

在代码本身中,甚至不需要创建选项:

var json = @"{
                 ""Id"": 1,
                 ""Name"": ""Some Name"",
                 ""Info"": {
                     ""Additional"": ""Fields"",
                     ""Are"": ""Inside""
                 }
             }";

var model = JsonSerializer.Deserialize<SomeModel>(json);

< code>Info属性中的原始JSON文本甚至包含示例中引入的额外空格,以提高可读性。

并且没有混合模型表示和它的序列化,正如@PavelAnikhomki在他的回答中所说。

 类似资料:
  • 问题内容: 我从看起来像这样的API获取JSON: 我尝试了几种方法来在c#对象中表示此JSON(太多内容无法在此处列出)。我已经尝试过使用列表和字典,这是我尝试表示它的最新示例: 这是我用来反序列化JSON的方法: 包含和。并且包含,但是是。因此,除了反序列化之外,什么都没有。 它应该很简单,但是由于某种原因我无法弄清楚正确的对象表示形式 问题答案: 要使用,即: 假设项目名称和随响应而变化,并

  • 问题内容: 如何将上述字符串反序列化为java对象。 我正在使用的类是 问题答案: @基达 我假设您可以控制JSON输入字符串的创建方式。我认为JSON字符串格式不正确,无法对地图类型进行默认的GSON反序列化。 我已经修改了输入字符串供您考虑,这将导致非null的LocalLocationId 如果我对输入字符串的假设不正确,请发表评论。 编辑1:由于无法修改输入,请考虑编写自定义解串器。以下是

  • 问题内容: 我有一些具有各种属性的JSON,其中大多数是简单数据类型。但是,我在JSON中有一个属性,当我将其反序列化为C#类时,我只需要将其反序列化为字符串即可。 JSON示例: 除了将是有效的JSON对象外,“ json”对象没有任何设置结构。 因此,在上面的示例中,“ json”的值是一个JSON对象-但是当它反序列化时,我需要将它作为字符串。 因此,如果我的C#类是: 然后,如果我使用:

  • 我尝试从一个用于存储Spring会话的Redis服务器反序列化String到Java对象,并且我想在Spring框架之外反序列化它。我认为Spring Redis序列化器可能使用默认字符集UTF-8来将Java对象序列化为字符串。 Redis中的字符串: 错误消息: 我知道用UTF-8在Byte[]和String之间的转换很可能是问题所在,但我还是想问一下,是否有人知道如何在不修改序列化部分的情况

  • 问题内容: 我有以下字符串 我想反序列化一个类的对象 我正在使用python 2.6和2.7 问题答案:

  • 问题内容: 我有一个名为的类,该类具有一个作为参数的构造函数: 具有以下属性: 并且是我的应用程序的其他类,并具有以下构造函数: ,并且是的子类。 我想用Gson 反序列化数组,所以我写道: 以定义为: 调试时,实例具有正确的“ MainActivity”作为上下文,而其成员变量的上下文为null。 Gson 使用正确的构造函数创建了对象,但使用默认的无参数构造函数创建了实例。我怎样才能解决这个问