0

I have a controller that returns a list of derived objects , a List of ICollectedEditionToGet to be precise, however when I try to serialize said objects it's only returning the properties that exist on the derived lass.

   public interface ICollectedEditionToGet : IBaseCollectedEdition
    {
        public string? Notes { get; set; }
    }

    public interface IBaseCollectedEdition
    {
        int Id { get; set; }

        string Title { get; set; }

        int Volume { get; set; }
    }

public abstract class BaseCollectedEditionModel : IBaseCollectedEdition
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int Volume { get; set; }
}

 public class CollectedEditionToGetModel : BaseCollectedEditionModel, ICollectedEditionToGet
    {
        public string Notes { get; set; }
}

 public async Task<IActionResult> GetCollectedEditionsToGet()
        {
            var CollectedEditionToGets = await Task.Run(() =>
            {
                return _service.TryGet();
            });
            return CollectedEditionToGets == null ? BadRequest() : Ok(JsonSerializer.Serialize(CollectedEditionToGets));
        }

[{"Notes":"Magic Bus"},{"Notes":"The Wake"},{"Notes":"The Immaterial Gir"},{"Notes":"First Born"},{"Notes":"Omnibus"},{"Notes":"Omnibus"},{"Notes":"All Different"},{"Notes":"Molecule Man"},{"Notes":"Motherland"},{"Notes":"Gouge Away"},{"Notes":"Dirge (Already Own, wrong trade dress!)"},{"Notes":null},{"Notes":"The Counterfifth Detective"},{"Notes":"Head of the Class"}]>

So my question is why, and what am I missing?

Updated to include interfaces.

user1708468
  • 195
  • 10
  • Some assumptions are made as you have not shared the interfaces but here is an example to see differences in results if your `_service.TryGet()` returns `CollectedEditionToGetModel` vs returning `ICollectedEditionToGet` https://dotnetfiddle.net/9Bhqt6 – Nope Mar 14 '23 at 12:10
  • Thanks guys, I have update my code to show the interfaces as well, but I will try both of the above. – user1708468 Mar 14 '23 at 12:26

2 Answers2

1

In versions prior to .NET 7, System.Text.Json doesn't support the serialization of polymorphic type hierarchies. this is by design.

See more details here: Serialize properties of derived classes


Using your code and NET 6 as an example, you can still get the desired result serializing your model as object.

JsonSerializer.Serialize<object>(CollectedEditionToGets);

Working Example using your code.


Using NET 7, as per documentation you can use the JsonDerivedType attribute instead.

[JsonDerivedType(typeof(CollectedEditionToGetModel))]
public interface IBaseCollectedEdition
{
    int Id { get; set; }

    string Title { get; set; }

    int Volume { get; set; }
}

Then when serializing you specify the base IBaseCollectedEdition instead of object

JsonSerializer.Serialize<IBaseCollectedEdition>(CollectedEditionToGets);

Working Example using NET 7


As an added thought.

When designing controllers I prefer using DTOs or similar in my responses, specially when serializing.

Our controllers call service wrappers that makes the service calls and then map the response to a specifically designed DTOs for that call.

A DTO is simple to serialize and deserialize without having to worry about derived types or using JSON attributes for derived types.

You also protect your controller from changes to abstraction as you only process the DTO which doesn't change if your underlying abstraction changes.

Nope
  • 22,147
  • 7
  • 47
  • 72
0

Just tried this , and both worked properly

var model = new List<CollectedEditionToGetModel> { new CollectedEditionToGetModel
    { Id = 1, Title = "Title", Volume = 5, Notes = "Some Notes"}};
    
Newtonsoft.Json.JsonConvert.SerializeObject(model); // [{"Notes":"Some Notes","Id":1,"Title":"Title","Volume":5}]
System.Text.Json.JsonSerializer.Serialize(model);// [{"Notes":"Some Notes","Id":1,"Title":"Title","Volume":5}]
Serge
  • 40,935
  • 4
  • 18
  • 45