We have a project which using System.Text.Json
in .NET 5 instead of Newtonsoft JObject
. Using Newtonsoft, it is pretty easy to replace dynamic JSON data e.g. as shown below:
siteDataObject["student"] = JArray.FromObject(studentservice.GetStudents());
When studentservice.GetStudents() is return List as below structure
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; }
}
but in System.Text.Json
foreach (var element in doc.RootElement.EnumerateObject()) {
if (element.Name == "student") {
writer.WritePropertyName(element.Name);
}
else {
element.WriteTo(writer);
}
}
I don't know how to convert List<student>
into JSON array data, when student class have many properties with multi collection inside.
Can anyone advise how to convert it ?
To clarify, I need to propose the full code for this, I have a dynamic json string and want to replace element : students into new record, the code will be
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());
I know how to modify student value , if student element is string, but I don't know how to modify it into array, by using simple code. As student have multi class inside.
My expected result should be
{
"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"
}
CodePudding user response:
I think this is what you want (array or single nested object):
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);
CodePudding user response:
In .NET 5 there is no modifiable JSON Document Object Model built into to System.Text.Json. JsonDocument
is read-only, and System.Text.Json.Nodes
was only introduced in .NET 6. Thus, the easiest way to deserialize, modify and re-serialize free-form JSON in .NET 5 is to deserialize to some partial data model, with unknown values bound into a dictionary.
If you do not care about the order of properties at the root level, you could deserialize to a model with a public object students { get; set; }
property, and bind the remaining elements to a JsonExtensionData
overflow dictionary:
public class RootObject
{
public object students { get; set; }
[System.Text.Json.Serialization.JsonExtensionDataAttribute]
public IDictionary<string, object> ExtensionData { get; set; }
}
Then deserialize, modify and re-serialize as follows:
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 });
Which results in
{
"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"
}
the students
property must be declared as object
because the input JSON already has an array containing a single integer value; declaring it as public List<Student> students { get; set; }
would result in a deserialization when initially loading the JSON.
Demo fiddle #1 here.
If you do care about the order of properties at the root level, you could deserialize to an OrderedDictionary
(an old order-preserving non-generic dictionary dating from .NET Framework 2.0 which is still around and supported), overwrite the "students"
value, and 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 });
Which results in
{
"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"
}
Demo fiddle #2 here.
In .NET 6 this all becomes easier through use of the System.Text.Json.Nodes
editable JSON Document Object Model:
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();
But in .NET 5 this is not possible. Demo fiddle #3 here.