Skip to content

Returning IActionResult and using an aggregate query produces non-OData JSON #1557

@joshcomley

Description

@joshcomley

Assemblies affected
Microsoft.AspNetCore.OData all of v8 and v9 as far as I can see.

Describe the bug
Run the ODataRoutingSample.

In the Customers controller, we return an IActionResult with an IQueryable:

public IActionResult Get()
{
    return Ok(GetCustomers());
}

If you call:

http://localhost:5000/v1/Customers

You will get an OData response:

{
  "@odata.context": "http://localhost:5001/v1/$metadata#Customers",
  "value": [
    {
      "Id": 1,
      "Name": "Jonier",
      "FavoriteColor": "Red",
      "Amount": 3,
      "HomeAddress": {
        "City": "Redmond",
        "Street": "156 AVE NE"
      },
      "FavoriteAddresses": [
        {
          "City": "Redmond",
          "Street": "256 AVE NE"
        },
        {
          "City": "Redd",
          "Street": "56 AVE NE"
        }
      ]
    },
    {
      "Id": 2,
      "Name": "Sam",
      "FavoriteColor": "Blue",
      "Amount": 6,
      "HomeAddress": {
        "@odata.type": "#ODataRoutingSample.Models.CnAddress",
        "City": "Bellevue",
        "Street": "Main St NE",
        "Postcode": "201100"
      },
      "FavoriteAddresses": [
        {
          "City": "Red4ond",
          "Street": "456 AVE NE"
        },
        {
          "City": "Re4d",
          "Street": "51 NE"
        }
      ]
    }
  ],
  "@odata.nextLink": "http://localhost:5001/v1/Customers?$skip=2"
}

But if you use an aggregate function:

http://localhost:5000/v1/Customers?$apply=groupby((FavoriteColor))

You will get a non-OData response:

[
  {
    "FavoriteColor": 0
  },
  {
    "FavoriteColor": 1
  }
]

However, if you return an IQueryable<T> directly and call the same aggregate query URL:

public IQueryable<Customer> Get()
{
    return GetCustomers().AsQueryable();
}

You get a proper OData response for the aggregate query:

{
  "@odata.context": "http://localhost:5001/v1/$metadata#Customers(FavoriteColor)",
  "value": [
    {
      "@odata.id": null,
      "FavoriteColor": "Red"
    },
    {
      "@odata.id": null,
      "FavoriteColor": "Green"
    }
  ],
  "@odata.nextLink": "http://localhost:5001/v1/Customers?$apply=groupby%28%28FavoriteColor%29%29&$skip=2"
}

Futher notes

If you return IQueryable only (not typed):

public IQueryable Get()
{
    return GetCustomers().AsQueryable();
}

You never get an OData response.

If you return IActionResult, do an aggregate query AND specify the DeclaredType in an OkObjectResult, you get the correct OData response back:

public IActionResult Get()
{
    return new OkObjectResult(GetCustomers())
    {
        DeclaredType = typeof(IQueryable<Customer>)
    };
}

Reproduce steps
Run the ODataRoutingSample and see the above steps.

Data Model
ODataRoutingSample - EdmModelBuilder.GetEdmModelV1()

EDM (CSDL) Model
NA

Request/Response
See above

Expected behavior
It should produce an OData response, even with an aggregate query returning an IActionResult.

Screenshots
NA

Additional context
NA

Metadata

Metadata

Assignees

Labels

P2bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions