AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

CosmosSDK with ODataQueryOptions breaks when using $select

Open Supernectar opened this issue 1 year ago • 3 comments

Assemblies affected ASP.NET Core OData 8.2.3 and Microsoft.Azure.Cosmos 3.35.4

Describe the bug Using the ODataQueryOptions.ApplyTo Method with the Container.GetItemLinqQueryable<T> Method throws an exception only, and only if the user provides a $select option in the url. Any other option such as $top, $skip, $filter work fine. Only when using $select the exception is thrown.

Reproduce steps

  1. Clone this repo https://github.com/Supernectar/ODataCosmosDBSelectBug.git
  2. Run the web app
  3. Make a GET request to any of these urls:
  • https://localhost:7234/customers?$select=id
  • https://localhost:7234/customers?$select=orders
  • https://localhost:7234/customers?$select=orders/amount
  1. See the exception being returned image

NOTE: You need to have a cosmosDB emulator running with a database named "TestDB" and a container named "test". Ideally this container should contain some sample data:

{
    "id": "c1429a3e-146c-4df7-8b9e-7c634b19f1a1",
    "name": "John Doe",
    "orders": [
        {
            "id": "f0c26d64-7e11-4ed1-8211-efae44f7f57d",
            "amount": 50.25,
            "type": 0
        },
        {
            "id": "5b4e0849-6b5c-4f75-9e75-86b48cb58353",
            "amount": 75.5,
            "type": 1
        }
    ]
}
{
    "id": "9e1a50a2-8e21-4f70-8f0a-ebbdac2b5e0f",
    "name": "Jane Smith",
    "orders": [
        {
            "id": "7273848c-f662-4e6b-b9ed-cd47d3d5e3fc",
            "amount": 30.75,
            "type": 1
        }
    ]
}
{
    "id": "ecb4e60f-5a82-4f10-aae0-06c3e8b21fe0",
    "name": "Bob Johnson",
    "orders": []
}

Data Model This is the main class where the exception is being generated:

public class CosmosService : ICosmosService
{
    private readonly CosmosClient _cosmosClient;

    public CosmosService(CosmosClient cosmosClient)
    {
        _cosmosClient = cosmosClient;

    }

    private Container Container
    {
        get => _cosmosClient.GetContainer("TestDB", "test");
    }

    public async Task<IEnumerable<Customer>> GetCustomers(ODataQueryOptions<Customer> queryOptions)
    {
        var customerList = new List<Customer>();

        var customerQueryable = Container.GetItemLinqQueryable<Customer>();

        ODataQuerySettings querySettings = new();

        customerQueryable = queryOptions.ApplyTo(customerQueryable, querySettings) as IOrderedQueryable<Customer>;

        using FeedIterator<Customer> setIterator = customerQueryable.ToFeedIterator();

        while (setIterator.HasMoreResults)
        {
            var result = await setIterator.ReadNextAsync();
            customerList.AddRange(result.Resource);
        }

        return customerList;
    }
}

You can check the rest of the code more in details in this example repo https://github.com/Supernectar/ODataCosmosDBSelectBug.git

Request/Response When doing a GET request to any of these urls

  • https://localhost:7234/customers?$select=id
  • https://localhost:7234/customers?$select=orders
  • https://localhost:7234/customers?$select=orders/amount This is the response I'm getting
System.ArgumentOutOfRangeException: ToFeedIterator is only supported on Cosmos LINQ query operations (Parameter 'linqQuery')
   at Microsoft.Azure.Cosmos.Linq.CosmosLinqExtensions.ToFeedIterator[T](IQueryable`1 query)
   at U4PIM.InvoiceManagementAPI.Services.CosmosService.GetCustomers(ODataQueryOptions`1 queryOptions) in C:\Users\GPATACA\source\repos\WebApplication1\Services\CosmosService.cs:line 33
   at WebApplication1.Controllers.CustomersController.Get(ODataQueryOptions`1 queryOptions) in C:\Users\GPATACA\source\repos\WebApplication1\Controllers\CustomersController.cs:line 20
   at lambda_method6(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Expected behavior I want to be able to use the $select option properly. Given the example data provided above, if I do a GET request to this url https://localhost:7234/customers?$select=orders/amount I want to receive the following data in the response body:

{
    "@odata.context": "https://localhost:7234/$metadata#Customers",
    "value": [
        {
            "Orders": [
                {
                    "Amount": 50.25
                },
                {
                    "Amount": 75.5
                }
            ]
        },
        {
            "Orders": [
                {
                    "Amount": 30.75
                }
            ]
        },
        {
            "Orders": []
        }
    ]
}

Supernectar avatar Sep 29 '23 02:09 Supernectar

Is this in any way related to:

  • https://github.com/OData/AspNetCoreOData/issues/87

?

julealgon avatar Sep 29 '23 13:09 julealgon

This seems to be related to this: https://github.com/OData/AspNetCoreOData/issues/1056 too. There is an open issue in the Cosmos SDK repo https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4096 that we are currently following up with.

ElizabethOkerio avatar Oct 03 '23 05:10 ElizabethOkerio

Is there a status update on this? This would be very useful to be fixed

CSharpFiasco avatar Aug 06 '24 17:08 CSharpFiasco