WebApi icon indicating copy to clipboard operation
WebApi copied to clipboard

ODataActionPayloadDeserializer failed to deserialize action parameter when it's a 2d array

Open cloudsere opened this issue 2 years ago • 4 comments

We defined an OData action with a 2d array parameter:

public IEnumerable<IEnumerable<object>> TestList { get; set; }

The OData entity model is registered as

<Action Name="TestAction">
    <Parameter Name="testList" Type="Collection(System.Collections.Generic.IEnumerable_1OfInt32)" />
</Action>

ODataActionPayloadDeserializer throws exception for this 2d array action parameter:

System.InvalidCastException: 'Unable to cast object of type 'Microsoft.AspNetCore.OData.Formatter.Wrapper.ODataResourceSetWrapper' to type 'Microsoft.AspNetCore.OData.Formatter.Wrapper.ODataNestedResourceInfoWrapper'.'

Assemblies affected

OData WebApi lib 7.2.2, I also tested latest main branch, it has the same issue.

Reproduce steps

It can be reproduced in unit test of ODataActionPayloadDeserializer

  1. Go to AspNetCoreOData\test\Microsoft.AspNetCore.OData.Tests\Formatter\Deserialization\ODataActionPayloadDeserializerTest.cs`
  2. Change schema of MyAddress as
public class MyAddress
    {
        public string StreetAddress { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public int ZipCode { get; set; }

        public IEnumerable<IEnumerable<int>> TestList { get; set; }
    }
  1. Construct test body in Can_DeserializePayload_WithComplexParameters as
const string Body = @"{ ""Quantity"": 1 , ""Address"": { ""StreetAddress"":""1 Microsoft Way"", ""City"": ""Redmond"", ""State"": ""WA"", ""ZipCode"": 98052, ""TestList"": [[1, 2, 3], [3, 4, 5]]} }";
  1. Run the test and see exception, if TestList is of IEnumerable<int> type, and if TestList in Body is of 1d array, everything works well.

Expected result

ODataActionPayloadDeserializer can correctly deserialize 2d array without throwing exceptions, if it's a Edm model registration error, please make the error message more clear.

cloudsere avatar Sep 28 '22 11:09 cloudsere

Tiny tips: Collection of the collection is not following up OData protocol. You can define a complex type to contain 'IEnumerable' property and use this complex type to define your 'TestList'.

xuzhg avatar Oct 04 '22 17:10 xuzhg

@xuzhg Thanks for letting me know, but I also find an issue here: https://github.com/OData/odata.net/issues/505 saying 2d array is supported, so maybe we just need to find a way to define a collection of Edm.Untyped type?

cloudsere avatar Oct 08 '22 01:10 cloudsere

@cloudsere Partial support for collection of collections is the form of collection of untyped or just untyped. We do not support a collection of primitive collections, i.e. (IEnumerable<IEnumerable<int>>). You'd need to define the property as IEnumerable<object>. However, this is currently not supported in 7x and the support may also be limited in 8x

gathogojr avatar Oct 11 '22 17:10 gathogojr

Because untyped provides limited support both in materialization and query options it's recommended to use a collection of complex types as suggested by @xuzhg above.

gathogojr avatar Oct 11 '22 17:10 gathogojr