Home > Back-end >  ASP.NET Core casts properties to base class
ASP.NET Core casts properties to base class

Time:12-09

I have two 'data' classes:

public class BaseData
{
    public string BaseDataStuff { get; set; }
}

public class ChildData : BaseData
{
    public string ChildDataStuff { get; set; }
}

and a 'container' class:

public class Container
{
    public BaseData Data { get; set; }
}

Then I have the following controller:

public class Controller : ControllerBase
{
    private readonly ChildData Data;
    private readonly Container Container;
    public Controller()
    {
        Data = new ChildData()
        {
            BaseDataStuff = "base stuff",
            ChildDataStuff = "child stuff"
        };

        Container = new Container()
        {
            Data = Data
        };
    }


    [HttpGet("data")]
    public ActionResult<BaseData> GetData() => Ok(Container.Data);

    [HttpGet("container")]
    public ActionResult<Container> GetContainer() => Ok(Container);

}

The first method just returns the ChildData instance. When I run it in swagger, I get the JSON I expect:

{
  "childDataStuff": "child stuff",
  "baseDataStuff": "base stuff"
}

When I run the second method through swagger, it looks like it casts the ChildData instance to BaseData. I get the following JSON:

{
  "data": {
    "baseDataStuff": "base stuff"
    }
}

Can someone explain what is happening here please?

CodePudding user response:

You could try serializing yourself like this

options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize<object>(Container, options);

or another option, is to explicitly mark them as serializable for the serializer:

  [DataContract]
  public class BaseData
  {
    [DataMember]
    public string BaseDataStuff { get; set; }
  }

  [DataContract]
  public class ChildData : BaseData
  {
    [DataMember]
    public string ChildDataStuff { get; set; }
  }

CodePudding user response:

This question was interesting. See How to serialize properties of derived classes with System.Text.Json

There it explains that System.Text.Json does not handle serializing polymorphic objects the way you want prior to .NET 7. There are some work arounds but those allow you to serialize when the root object is polymorpic (Container in you case) but not members of the root (BaseData and ChildData).

In .NET 7 you can do this

using System.Text.Json.Serialization;

[JsonDerivedType(typeof(ChildData))]
public class BaseData
{
    public string BaseDataStuff { get; set; } = string. Empty;
}

and

public class ChildData : BaseData
{
    public string ChildDataStuff { get; set; } = string. Empty;
}

and

public class Container
{
    public BaseData Data { get; set; } = new BaseData();
}

Then this

var data = new ChildData()
        {
            BaseDataStuff = "base stuff",
            ChildDataStuff = "child stuff"
        };

var container = new Container 
{
    Data = data
};

jsonString = JsonSerializer.Serialize(container);
Console.WriteLine(jsonString);

gives you

{"Data":{"ChildDataStuff":"child stuff","BaseDataStuff":"base stuff"}}

Which I think is what you want. Of course, going to .NET 7 may not be convenient.

  • Related