My team and I came accross a weird behavior with JSON.NET deserialization in C#.
We have a simple ViewModel with a IOrderedEnumerable<long>
:
public class TestClass
{
public IOrderedEnumerable<long> orderedDatas { get; set; }
public string Name { get; set; }
public TestClass(string name)
{
this.Name = name;
this.orderedDatas = new List<long>().OrderBy(p => p);
}
}
Then, we just want to POST/PUT this viewmodel in an API controller
[HttpPost]
public IHttpActionResult Post([FromBody]TestClass test)
{
return Ok(test);
}
Calling this API with a json that look like that :
{
Name: "tiit",
"orderedDatas": [
2,
3,
4
],
}
With this call, we saw that the constructor wasn't called (which can be explained by the fact that it's not a default constructor). But the strange thing is that if we change the type of the collection to IEnumerable
or IList
, the constructor is properly called.
If we change the constructor of TestClass
to be a default one :
public class TestClass
{
public IOrderedEnumerable<long> orderedDatas { get; set; }
public string Name { get; set; }
public TestClass()
{
this.Name = "default";
this.orderedDatas = new List<long>().OrderBy(i => i);
}
}
The object retrieve by the controller will not be null.
And if we change the type of the collection to IEnumerable
and we keep the constructor with a parameter (public TestClass(string name)
), it'll work also.
Another strange thing is that the object test in the controller is "null". Not only the orderedDatas is null, but the entire object.
If we add an attribute [JsonObject]
on the class, and an [JsonIgnore]
on the property orderedData, it works.
For now, we changed the object to a simple List and it's working fine, but we were wondering why the JSON deserialization act different depending on the type of the collection.
If we use directly the JsonConvert.Deserialize :
var json = "{ Name: 'tiit', 'orderedDatas': [2,3,4,332232] }";
var result = JsonConvert.DeserializeObject<TestClass>(json);
we can saw the actual exception :
Cannot create and populate list type System.Linq.IOrderedEnumerable`1[System.Int64]. Path 'orderedDatas', line 1, position 33.
Any idea / help is appreciated.
Thanks !
** Edit : thanks for your answers. There is one thing that I keep finding weird (I put it in bold), if you have any idea to explain this behavior, please tell me **