等同于 .Net5 中的 JArray.FromObject()?

Equivalent of JArray.FromObject() in .Net5?

我们有一个项目在 .NET 5 中使用 System.Text.Json 而不是 Newtonsoft JObject。使用 Newtonsoft,替换动态 JSON 数据非常容易,例如如下图:

siteDataObject["student"] = JArray.FromObject(studentservice.GetStudents());

当studentservice.GetStudents()为return结构如下

internal class Student {
    public int Id { get; set; }
    public string Name { get; set; }
    public string ContactPhone { get; set; }

    public IEnumerable<MedicalRecord> MedicalRecords { get; set; }
}

internal class MedicalRecord {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime RecordDate { get; set; }
    public IEnumerable<DiseaseLog> DiseaseLogs{ get; set; }
}

internal class DiseaseLog {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime LogDate { get; set; }
}

但在System.Text.Json

foreach (var element in doc.RootElement.EnumerateObject()) {
    if (element.Name == "student") {
        writer.WritePropertyName(element.Name);
    
    }
    else {
        element.WriteTo(writer);
    }
}

我不知道如何将 List<student> 转换成 JSON 数组数据,当学生 class 有很多属性,里面有多个集合。

谁能告诉我如何转换它?

为了澄清,我需要为此提出完整的代码,我有一个动态 json 字符串并想将元素 : students 替换为新记录,代码将是

var dynamicJson = @"{'roomid':1,'roomcode':'Code001','students':[1],'contentdata':'say hello','footerdata':'cookie policy'}";
using MemoryStream stream = new MemoryStream();
using Utf8JsonWriter writer = new Utf8JsonWriter(stream);
using var dynamicDocument = JsonDocument.Parse(dynamicJson);
writer.WriteStartObject();
foreach (var element in dynamicDocument.RootElement.EnumerateObject())
{
    if (element.Name == "students")
    {
        // unknown how to modify the student record into array
    }
    else
        element.WriteTo(writer);
}
writer.WriteEndObject();
stream.Flush();
var modifyJson = Encoding.UTF8.GetString(stream.ToArray());

如果学生元素是字符串,我知道如何修改学生值,但我不知道如何使用简单的代码将其修改为数组。因为学生里面有多个class。

我的预期结果应该是

{
    "roomid": 1,
    "roomcode": "Code001",
    "students": [
        {
            "id": 1,
            "Name": "Wilson",
            "ContactPhone": "123-122-3311",
            "MedicalRecords": [
                {
                    "id": 101,
                    "Name ": "Medial record 101011",
                    "RecordDate": "2021-12-31",
                    "DiseaseLogs": [
                        {
                            "id": 18211,
                            "Name ": "Patient Log 19292",
                            "LogDate": "2020-1-31"
                        },
                        {
                            "id": 18212,
                            "Name ": "Patient Log 2911w",
                            "LogDate": "2020-3-31"
                        }
                    ]
                }
            ]
        }
    ],
    "contentdata": "say hello",
    "footerdata": "cookie policy"
}

我想这就是你想要的(数组或单个嵌套对象):

var student = new Student()
{
    Name = "Student",
    ContactPhone = "contact",
    Id = 1,
    MedicalRecords = new List<MedicalRecord>()
    {
        new MedicalRecord()
        {
            Name = "Medical Record 1",
            RecordDate= DateTime.Now ,
            Id = 1 ,
            MedicalRecords = new List<DiseaseLog>()
            {
                new DiseaseLog(){ Name = "some disease" ,
                    LogDate = DateTime.Now, Id =1  }
            }
        }
    }
};

var data = System.Text.Json.JsonSerializer.Serialize(student);
Console.WriteLine(data);


var list = new List<Student>();
list.Add(student);

var arrayData = System.Text.Json.JsonSerializer.Serialize(list);

Console.WriteLine(arrayData);

在 .NET 5 中,System.Text.Json 中没有可修改的 JSON 文档对象模型。 JsonDocument is read-only, and System.Text.Json.Nodes 仅在 .NET 6 中引入。因此,反序列化、修改和 re-serialize free-form JSON 在 .NET 5[=57 中的最简单方法=] 是反序列化为一些部分数据模型,将未知值绑定到字典中。

如果您不关心根级别的属性顺序,您可以反序列化为具有 public object students { get; set; } 属性 的模型,并将其余元素绑定到 JsonExtensionData 溢出字典:

public class RootObject
{
    public object students { get; set; }

    [System.Text.Json.Serialization.JsonExtensionDataAttribute]
    public IDictionary<string, object> ExtensionData { get; set; }
}

然后反序列化,修改和re-serialize如下:

var students = new List<Student> { /* Initialize these as required... */ };

var dynamicJson = @"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";

var root = JsonSerializer.Deserialize<RootObject>(dynamicJson);

root.students = students;

var modifyJson = JsonSerializer.Serialize(root, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true });

结果是

{
  "students": [
    {
      "id": 1,
      "name": "Wilson",
      "contactPhone": "123-122-3311",
      "medicalRecords": [
        {
          "id": 101,
          "name": "Medial record 101011",
          "recordDate": "2021-12-31T00:00:00",
          "diseaseLogs": [
            {
              "id": 18211,
              "name": "Patient Log 19292",
              "logDate": "2020-01-31T00:00:00"
            },
            {
              "id": 18212,
              "name": "Patient Log 2911w",
              "logDate": "2020-03-31T00:00:00"
            }
          ]
        }
      ]
    }
  ],
  "roomid": 1,
  "roomcode": "Code001",
  "contentdata": "say hello",
  "footerdata": "cookie policy"
}

students 属性 必须声明为 object 因为输入 JSON 已经有一个包含单个整数值的数组;将其声明为 public List<Student> students { get; set; } 会在最初加载 JSON.

时导致反序列化

演示 fiddle #1 here.

如果您确实关心根级别的属性顺序,您可以反序列化为 OrderedDictionary(旧的 order-preserving non-generic 字典,可追溯到 .NET Framework 2.0仍然存在并受支持),覆盖 "students" 值,并且 re-serialize:

var students = new List<Student> { /* Initialize these as required... */ };

var dynamicJson = @"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";

var root = JsonSerializer.Deserialize<OrderedDictionary>(dynamicJson);

root["students"] = students;

var modifyJson = JsonSerializer.Serialize(root, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true });

结果是

{
  "roomid": 1,
  "roomcode": "Code001",
  "students": [
    {
      "id": 1,
      "name": "Wilson",
      "contactPhone": "123-122-3311",
      "medicalRecords": [
        {
          "id": 101,
          "name": "Medial record 101011",
          "recordDate": "2021-12-31T00:00:00",
          "diseaseLogs": [
            {
              "id": 18211,
              "name": "Patient Log 19292",
              "logDate": "2020-01-31T00:00:00"
            },
            {
              "id": 18212,
              "name": "Patient Log 2911w",
              "logDate": "2020-03-31T00:00:00"
            }
          ]
        }
      ]
    }
  ],
  "contentdata": "say hello",
  "footerdata": "cookie policy"
}

演示 fiddle #2 here.


在 .NET 6 中,通过使用 System.Text.Json.Nodes 可编辑的 JSON 文档对象模型,这一切变得更加容易:

var dynamicJson = @"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";

var nodes = JsonSerializer.Deserialize<JsonObject>(dynamicJson);

nodes["students"] = JsonSerializer.SerializeToNode(students, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });

var modifyJson = nodes.ToString();

但在 .NET 5 中这是不可能的。演示 fiddle #3 here.