In a C# WebApi project, the API controller has a public method, accepting a parameter of List. When I define T as dynamic, or object, it works. However, when I define T as MyClass it comes with .Count == 0. I even tried using a public interface IMyClass, but has the same behaviour. We are using Swagger for the tests, not sure if this is the reason.
Controller method:
public async Task<int> SaveData(List<MyClass> list) { ...code here...}
MyClass:
public MyClass : IMyClass
{
public MyClass(int id, string name)
{
ID = id;
Name = name;
}
public MyClass(int id, string name, List<IOtherClass> otherList)
{
ID = id;
Name = name;
OtherList = otherList;
}
public int ID { get; }
public string Name { get; }
public List<IOtherClass> OtherList { get; set; }
}
MyOtherClass:
public MyOtherClass : IMyOtherClass
{
public MyOtherClass(int id, string name)
{
ID = id;
Name = name;
}
public int ID { get; }
public string Name { get; }
}
Interfaces:
public interface IMyClass
{
int ID { get; }
string Name { get; }
List<IMyOtherClass> OtherList { get; set; }
}
public interface IMyOtherClass
{
int ID { get; }
string Name { get; }
}
JSON passed:
[
{
"id": 123,
"name": "Test name",
"otherList": [
{
"id": 345,
"name": "Another name"
}
]
}
]
Actual classes are pretty much the same, nothing complicated. I tried using both MyClass and IMyClass as input parameters. Also tried IEnumerable instead of List In all cases "list" is not null, but has "list.Count == 0" But if I use "List< dynamic > list" then "list.Count == 1", as it should be.
What am I missing here?
CodePudding user response:
MyClass
has a couple issues, that make it unable to be deserialized :
No public parameterless constructor, this makes it so that the deserialization framework, cannot create an instance.
To resolve, either create a parameterless constructor or annotate one of the constructors with
[JsonConstructor]
If you went the way of creating a parameterless constructor, then the next issue become that you have only getters, so the value won't be able to be set during deserialization.
OtherList
is a list of an interface type, unless the json you are deserializing includes the concrete type, (metadata $type in the json) and the deserializer is configured to take it into account, it won't know which concrete type to use for the childs.
For the case of the properties names, see @Marc's answer or How to enable case-insensitive property name matching (MSDN)
CodePudding user response:
Your JSON contain lowercase names, however you classes have PascalCase property names.
You can try and change your JSON to have PascalCase names, or you can add the JsonProperty attribute to your MyClass properties to specify the binding, here's the Name property as an example:
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }