0

In a new .NET 5 project, I have a List<BaseClass> as a property on a ViewModel. It has 4 properties on it. At runtime, I populate that list with 4 different derived classes, each with about 3 distinct properties of their own, in addition to the base class.

When I return this in a JsonResult from a controller, I'm only getting the BaseClass properties serialized in the list, when I want all the derived class properties on each respective class.

I'm not using Newtonsoft.Json, just the built in System.Text.Json. How can I configure it across the app to serialize the derived class properties? I'm coming up short on trying to find code examples / similar questions, that are not Newtonsoft.Json based.


I just found these docs that tells me how to solve this problem when I'm manually doing the serialization. But I need it to work within the mvc framework

Jonesopolis
  • 25,034
  • 12
  • 68
  • 112
  • If you won't find a solution to make this work with System.Text.Json (I usually replace it with newtonsoft one so don't really know the solution there) to do what you need it to do you can always create your own Json string and return a contentresult with content=application/json. Here are some examples on how to do that https://stackoverflow.com/questions/9777731/mvc-how-to-return-a-string-as-json – Andrej Dobeš Jul 17 '22 at 22:31

1 Answers1

1

I ended up finding a converter someone wrote, and tweaked it a bit for my case (my model is called CartLineItem)

public class CartLineItemConverter : JsonConverter<CartLineItem>
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeof(CartLineItem).IsAssignableFrom(typeToConvert);
    }

    public override CartLineItem Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, CartLineItem value, JsonSerializerOptions options)
    {
        if (value is null)
        {
            writer.WriteNullValue();
            return;
        }

        writer.WriteStartObject();

        foreach (var property in value.GetType().GetProperties())
        {
            if (!property.CanRead)
            {
                continue;
            }

            var propertyValue = property.GetValue(value);
            writer.WritePropertyName(property.Name);
            JsonSerializer.Serialize(writer, propertyValue, options);
        }

        writer.WriteEndObject();
    }
}

Apparently System.Text.Json does not have support for a global config, but I found I can apply that in my Startup class to the MVC pipeline -

 services.AddControllers()
         .AddJsonOptions(x =>
         {
             x.JsonSerializerOptions.Converters.Add(new CartLineItemConverter());
         });

Once I did that, I saw all the distinct properties coming back in the list of CartLineItems.

Jonesopolis
  • 25,034
  • 12
  • 68
  • 112