【问题标题】:Add a root element to an object while serializing to JSON using System.Text.Json在使用 System.Text.Json 序列化为 JSON 时向对象添加根元素
【发布时间】:2020-07-10 13:33:15
【问题描述】:

所有, 在执行以下代码时,我们遇到了以下异常(粗体),我们试图将根节点“test”添加到最终的 json 结果中。我们希望在没有匿名对象或包装类的情况下实现这一目标。

“无法将 JSON 属性写入数组或作为第一个 JSON 标记。当前标记类型为“无”。

 internal static class Program
    {
        public static void Main(string[] args)
        {
            customer cust = new customer();
            cust.firstname = "first";
            cust.lastname = "last";

            Console.WriteLine(AddRootToJson("test", cust));
        }

        public static string AddRootToJson(string root, object obj)
        {
            var msSt = new MemoryStream {Position = 0};
            using var utf8JsonWriter = new Utf8JsonWriter(msSt);
            utf8JsonWriter.WriteStartObject(root);
            JsonSerializer.Serialize(utf8JsonWriter, obj);
            utf8JsonWriter.WriteEndObject();
            utf8JsonWriter.Flush();
            using var reader = new StreamReader(msSt);
            return reader.ReadToEnd();
        }
    }


    public class customer
    {
        public string firstname;
        public string lastname;
    }

【问题讨论】:

  • 什么是“根元素”?你想要{"test": {"firstname": "", "lastname": ""}}这样的东西吗?
  • 是否有理由不将该属性添加到Customer 类?是不是因为你在输出中只需要这个属性,而在应用程序的其他地方不需要?
  • 我知道你说“没有包装器”,但是你可以创建一个通用的包装器。类 JsonNeedsSingleRootWorkaround { public string Uid { get;私人套装; } = Guid.NewGuid().ToString("N"); /* 这是一个处理 json 序列化问题的 List */ public List Items { get;放; } }

标签: c# system.text.json


【解决方案1】:

首先,目前System.Text.Json 不支持序列化字段,因此您需要更改您的类(请参阅docs 中的对公共和非公共字段的支持):

public class customer
{
    public string firstname {get;set;}
    public string lastname {get;set;}
}

之后你可以尝试下一步:

public static string AddRootToJson(string root, object obj)
{
    using var msSt = new MemoryStream();
    using var utf8JsonWriter = new Utf8JsonWriter(msSt);
    utf8JsonWriter.WriteStartObject();
    utf8JsonWriter.WritePropertyName(root);
    JsonSerializer.Serialize(utf8JsonWriter, obj);
    utf8JsonWriter.WriteEndObject();
    utf8JsonWriter.Flush();
    return Encoding.UTF8.GetString(msSt.ToArray());
}

Console.WriteLine(AddRootToJson("test", new customer {firstname = "first", lastname = "last"})); // prints {"test":{"firstname":"first","lastname":"last"}}

【讨论】:

  • 如果您在 .NET Core 上运行,并且性能很重要,那么您可以使用 ArrayBufferWriter<byte> 而不是使用 MemoryStream 然后在其上调用 .ToArray(),而是使用 ArrayBufferWriter<byte> 并保存额外的分配.在Flush 调用Encoding.UTF8.GetString(ReadOnlySpan<Byte>) 之后传入WrittenSpan 属性docs.microsoft.com/en-us/dotnet/api/…
【解决方案2】:

如果我理解你的正确你想要的结果是这样的:

{"test",
    [
      {"first",
      "last"}
      ....
    ]
}

只需为它创建另一个模型:

public class FullModel
{
    public List<Customer> Customers {get;set;}
    public string Root {get;set;}
}

并更改您的客户类别:

public class Customer
{
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

现在,一步一步来:

public static void Main(string[] args)
    {
        List<Customer> customers = new List<Customers>();
        customers.Add(new Customer{FirstName="first",LastName="last"});
        FullModel fullModel = new FullModel
        {
            Root = "test",
            Customers = customers
        };
         
        Console.WriteLine(AddRootToJson(cust));
    }

public static string AddRootToJson(object obj)
    {
        var msSt = new MemoryStream {Position = 0};
        using var utf8JsonWriter = new Utf8JsonWriter(msSt);
        JsonSerializer.Serialize(utf8JsonWriter, obj);
        utf8JsonWriter.WriteEndObject();
        utf8JsonWriter.Flush();
        using var reader = new StreamReader(msSt);
        return reader.ReadToEnd();
    }

您可以根据自己的观点更改方法。 希望它会帮助你。祝你好运。

【讨论】:

  • OP 特别写道“我们希望在没有匿名对象或包装类的情况下实现这一目标。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-16
  • 2023-03-28
  • 2010-10-18
  • 1970-01-01
相关资源
最近更新 更多