skip to Main Content

How can I let the JSON serializer ignore the enumeration of a class and serialize it as object and list its properties only?

Here is an example of my problem:

public class ObjectList<T> : IEnumerable<T> where T : class
{
    public ObjectList()
    {
        this.Items = new List<T>();
    }

    public string Group { get; set; }
    public int Count { get => this.Items.Count; set { } }
    public List<T> Items { get; set; }

    public IEnumerator<T> GetEnumerator() { return this.Items.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return this.Items.GetEnumerator(); }
}

public class ItemList : ObjectList<ListItem>
{
}

Assuming the following content:

var list = new ItemList() 
    {
        Group = "Group",
        Items = new List<ListItem>()
        {
            new ListItem() { Name = "Foo"},
            new ListItem() { Name = "Bar"},
        }
    };

Now when I serialize the content using this code:

var txt = System.Text.Json.JsonSerializer.Serialize(list, new JsonSerializerOptions()
                           { WriteIndented = true, });
Console.WriteLine(txt);

I get the following output

[ { "Name": "Foo" }, { "Name": "Bar" } ]

The properties of the list object (Group, Count, Items) are not listed. The result I expect would be as following:

{ 
    "Group": "Group", 
    "Count": 2, 
    "Items": [ { "Name": "Foo" }, { "Name": "Bar" } ]
}

Removing the enumeration from the main class is not an option. So I need to tell the serializer to handle the class ItemList as an object rather than enumeration.

Can you help me on that point?

Thank you in advance.

2

Answers


  1. You should implement the custom JSON converter for the ItemList class.

    using System.Text.Json.Serialization;
    using System.Reflection;
    
    public class ItemListJsonConverter : JsonConverter<ItemList>
    {
        public override ItemList Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options) =>
               throw new JsonException("Not supported for deserialization");
    
        public override void Write(
            Utf8JsonWriter writer,
            ItemList value,
            JsonSerializerOptions options)
            {
                writer.WriteStartObject();
    
                PropertyInfo[] propInfos = typeof(ItemList).GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var prop in propInfos)
                {
                    string propertyName = prop.Name.ToString();
                    writer.WritePropertyName
                        (options.PropertyNamingPolicy?.ConvertName(propertyName) ?? propertyName);
    
                    JsonSerializer.Serialize(writer, prop.GetValue(value), options);
                }
    
                writer.WriteEndObject();
            }
    }
    

    Next, register the ItemListJsonConverter instance into the Converters for the JsonSerializerOptions instance.

    var jsonSerializerOptions = new JsonSerializerOptions() { WriteIndented = true };
    jsonSerializerOptions.Converters.Add(new ItemListJsonConverter());
    var txt = System.Text.Json.JsonSerializer.Serialize(list, jsonSerializerOptions);
    
    Login or Signup to reply.
  2. Is your ObjectList class with the Group and Count properties needed somewhere else, or is it only used for the desired serialization?

    Why not use a standard List<T>? And use DTO for serialization. Moreover it can be made anonymous.

    var list = new List<ListItem>()
    {
        new ListItem { Name = "Foo"},
        new ListItem { Name = "Bar"}
    };
    
    var listDTO = new { Group = "Group", Count = list.Count, Items = list };
    
    var options = new JsonSerializerOptions() { WriteIndented = true };
    
    var txt = JsonSerializer.Serialize(listDTO, options);
    Console.WriteLine(txt);
    

    See here (the benchmark is at the end of the section) why the JsonSerializerOptions instance should be cached and reused.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search