简体   繁体   中英

.NET Core 3 Web API: [FromBody] how bind abstract class property

I have class hierarchy for API model request:

public class Human
{
    public string Name { get; set; }
    public byte Age { get; set; }
    public IEnumerable<HumanData> Data { get;  set; }
}

public abstract class HumanData
{
    public Guid Id { get; set; }
    public string Text { get; set; }
    public virtual string Type => GetType().Name;
}

public class HealthData : HumanData
{
    public byte Weight { get; set; }
    public byte Growth { get; set; }
    public string Pressure { get; set; }
}

public class AddressData : HumanData
{
    public string City { get; set; }
    public string Street { get; set; }
    public uint House { get; set; }
    public uint Apartment { get; set; }
}

I created API for adding human:

[ApiController]
public class HumanController : ControllerBase
{
    ...

    [HttpPost]
    public async Task<IActionResult> Add([FromBody] Human humanRequest)
    {
        //Functionality
    }
}

I call the API and pass request model:

{
"Name":"Alex",
"Age":30
"Data":[{
    "Id": "10",
    "Text":"Residence address",
    "City":"Elblag",
    "Street":"1 maja",
    "House":"95",
    "Type":"AddressData",
},{
    "Id": "5",
    "Text":"Residence address",
    "Weight":"75",
    "Growth":"179",
    "Pressure":"120/85",
    "Type":"HealthData",
}]}

But the request model is not pulled in humanRequest variable. The reason is in the Data field HumanData class hierarchy. How to make such a binding?

The only way you can get your model if you change your action signature like this

[HttpPost]
    public async Task<IActionResult> Add([FromBody] JObject humanRequest)
    {

        //Functionality
    }
but you will have untyped Object in this case and you have to read it like this:
var name=humanRequest["Name"].ToString();

Much better way if your data structure will be changed to something like this:

public class Human
{
   public Guid Id { get; set; }
  
    public string Name { get; set; }
    public byte Age { get; set; }
public Guid AddressId {get;set;}
public Guid HealthId {get;set;}
    public virtual AddressData Address { get;  set; }
 public virtual HealthData Health { get;  set; }
}

public class HealthData
{
public Guid Id {get; set;}
  public string Text { get; set; }
    public byte Weight { get; set; }
    public byte Growth { get; set; }
    public string Pressure { get; set; }
}

public class AddressData 
{
public Guid Id {get; set;}
  public string Text { get; set; }
    public string City { get; set; }
    public string Street { get; set; }
    public uint House { get; set; }
    public uint Apartment { get; set; }
}

Your Json model should look like this

{
Id: "0f8fad5b-d9cb-469f-a165-70867728950e"
"Name":"Alex",
"Age":30,
AddressId="0f8fad5b-d9cb-469f-a165-70867728950e",
HealthId="0f8fad5b-d9cb-469f-a165-70867728950d",
"Address":{
    "Id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "Text":"Residence address",
    "City":"Elblag",
    "Street":"1 maja",
    "House":"95",
    "Type":"AddressData"
},
"Health":{
    "Id": "0f8fad5b-d9cb-469f-a165-70867728950d",
    "Text":"Residence address",
    "Weight":"75",
    "Growth":"179",
    "Pressure":"120/85",
    "Type":"HealthData"
}
}

But honestly I don't see why you need 3 tables for Human. You will have one-to-one relations in the most cases. I would consider to merge all this 3 tables in 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM