0

Let's say we have these C# classes:

public class Teacher
{
    public long Id { get; set; }
    public string Name { get; set; }
    public boolean IsActive { get; set; }
    public dynamic RelatedItems { get; set; }
}
public class Student
{
    public long Id { get; set; }
    public string Name { get; set; }
    public double AverageScrore { get; set; }
    public dynamic RelatedItems { get; set; }
}
public class Course
{
    public long Id { get; set; }
    public string Title { get; set; }
}

And here's the object graph that is built:

var teacher = teacherService.Get(teacherId);
teacher.RelatedItems.Students = studentService.GetByTeacherId(teacherId);
foreach (var student in teacher.RelatedItems.Students)
{
    student.RelatedItems.Courses = courseService.GetStudentCourses(studentId);
}

The object graph above produces this JSON after serialization (using System.Text.Json):

{
    "Id": "5",
    "Name": "John",
    "IsActive": true,
    "RelatedItems": {
        "Students": [
            {
                "Id": 7,
                "Name": "Joe",
                "AverageScore": 9.3,
                "RelatedItems": {
                    "Courses": [
                        {
                            "Id": 12,
                            "Title": "Math"
                        }
                    ]
                }
            }
        ]
    }
}

What I need to do is to remove those RelatedItems in the serialized JSON, and move their children one step up. This would be the result:

{
    "Id": "5",
    "Name": "John",
    "IsActive": true,
    "Students": [
        {
            "Id": 7,
            "Name": "Joe",
            "AverageScore": 9.3,
            "Courses": [
                {
                    "Id": 12,
                    "Title": "Math"
                }
            ]
        }
    ]
}

Is it possible to be done via System.Text.Json?

Hossein Fallah
  • 1,859
  • 2
  • 18
  • 44
  • 1
    What if modify your classes by removing the `RelatedItems` property, and redesign your classes based on your desired JSON output? – Yong Shun Feb 05 '22 at 04:32
  • @YongShun, of course that is the best option. But I don't have access to the classes. – Hossein Fallah Feb 05 '22 at 05:23
  • 1
    Writing a Custom JSON converter is one of the alternatives. But I am not so familiar with it and sometimes writing the converter may take too much effort and time. Another *cheating* way is to create a DTO class for your JSON output. Manually map the existing value to the DTO class or using tools like [AutoMapper](https://automapper.org/). – Yong Shun Feb 05 '22 at 07:07
  • Why are you even using classes you "don't have access to"? – Caius Jard Feb 05 '22 at 07:55
  • @CaiusJard, what do you mean? When you use Microsoft classes, do you have access to? When you use thousands of libraries, open-source or closed-source, do you literally have access to? Are you going to change something entirely just because it's a third-party library? I don't understand what you mean. – Hossein Fallah Feb 05 '22 at 07:57
  • It's so trivial to make a POCO class that suits your needs; why use one that hamstrings you to a workaround? – Caius Jard Feb 05 '22 at 09:03
  • @CaiusJard, it's better to find a centralized solution, than creating hundreds of POCO in a real-world problem. Of course what I wrote here is a sample to represent the issue. It's part of a real-world project with hundreds of tables and classes and ... – Hossein Fallah Feb 05 '22 at 09:35
  • *and ...* an intrinsic flaw.. I feel your pain – Caius Jard Feb 05 '22 at 10:41

1 Answers1

0

You have to write custom classes for serialization

var options = new JsonSerializerOptions();
options.Converters.Add(new CustomJsonConverter());
json = JsonSerializer.Serialize(StudentClassObject, options);

Implementation of CustomJsonConverter

public class CustomJsonConverter : JsonConverter<Student>
{
    public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Use default implementation when deserializing (reading)
        return JsonSerializer.Deserialize<Book>(ref reader, options);
    }

    public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
        {
            foreach (var property in document.RootElement.EnumerateObject())
            {
                if (property.Name != "RelatedItems")
                    property.WriteTo(writer);
            }
        }

        writer.WriteEndObject();
    }    

}
Ajay Gupta
  • 703
  • 5
  • 11