odata.net
odata.net copied to clipboard
JSON Body deserialization doesn't error when a non-primitive collection contains a primitive
When deserializing the JSON Body of a HTTP POST request, and when the model contains a collection of a non-primitive type, if the POST Body specifies a primitive type as one of the entities in this collection then no error is observed.
For example, if the model for ProductFamily
is:
public class ProductFamily
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
}
Then a HTTP POST request to create a ProductFamily
that demonstrates the bug has this POST Body:
{
"Id": 9,
"Products": ["Hello"]
}
The corresponding response should be a 400 Bad Request
(and this is the behaviour in version 7.1.0
), because in the JSON, Products
is an array with 1 item -- "Hello"
-- however that JSON array containing a string can't be deserialized into ICollection<Product>
because string
is not the same type as Product
.
Whereas in version 7.2.1
and later, what happens is that the string "Hello"
is dropped on the floor, and the controller method is called with an empty list, which means that it will return a 201 Created
.
Assemblies affected
This bug was introduced in the NuGet package Microsoft.AspNetCore.OData
version 7.2.1
(version 7.1.0
works correctly).
I think that the root cause is code in Microsoft.AspNet.OData.Shared
and specifically in the class Microsoft.AspNet.OData.Formatter.Deserialization.ODataReaderExtensions
Reproduce steps
- Load the sample https://github.com/DavidSimner/ODataSamples/tree/patch-1/WebApiCore/ODataServiceSample (this is a fork of the
ODataSamples
repo, the only change is https://github.com/OData/ODataSamples/pull/134) - Start the project
ODataService.Web
- Make a HTTP POST request to
/odata/ProductFamilies
with the POST Body:
{
"Id": 9,
"Products": ["Hello"]
}
Expected result
The HTTP request should fail with a 400 Bad Request
-- this is the behaviour observed in version 7.1.0
Actual result
The HTTP request succeeds with a 201 Created
-- this is the behaviour observed in version 7.2.1
and later.
Additional detail
When deserializing the example above, a Contract.Assert
detects the issue, see: https://github.com/OData/WebApi/blob/1b6c9bf59bf605b4462234db147cf6c2797025a6/src/Microsoft.AspNet.OData.Shared/Formatter/Deserialization/ODataReaderExtensions.cs#L134
@DavidSimner you can get an error message in the ModelState from the controller.
@ElizabethOkerio I am also facing this exactly same issue. Also ModelState does not contain any error message.
@ElizabethOkerio We are currently on Microsoft.AspNetCore.OData 8.0.10 and still seeing this issue.
Fixed by #2072 Fell free to create a new issue if it still persists