InvalidOperationException when returning ODataController.Created in a custom bound action
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 505
- Forks
- 186
- PR merge metrics
- No merged PRs in 30d
Description
Issue description
Hi Sam, I have a custom OData action bound with the namespace and return type properly setup. However, I noticed that using the ODataController.Created return instead of Ok return in my controller implementation causes the below InvalidOperationException. I expected that Created is the more correct return type; however, using Ok appears to work just as well and all the odata query parameters appear to work still as expected (e.g. $select, $expand, etc.).
System.InvalidOperationException: The related entity set or singleton cannot be found from the OData path. The related entity set or singleton is required to serialize the payload.
at Microsoft.AspNetCore.OData.Results.ResultHelpers.GenerateODataLink(HttpRequest request, Object entity, Boolean isEntityId) in Microsoft.AspNetCore.OData.dll:token 0x60002b5+0x43
at Microsoft.AspNetCore.OData.Results.CreatedODataResult`1.GenerateLocationHeader(HttpRequest request) in Microsoft.AspNetCore.OData.dll:token 0x60002a6+0x0
at Microsoft.AspNetCore.OData.Results.CreatedODataResult`1.ExecuteResultAsync(ActionContext context) in Microsoft.AspNetCore.OData.dll:token 0x60002a3+0x86
...
I tried to see if any of your sample code uses Created for custom actions but it looks like the only custom action implementation present uses Ok instead and this code has been commented out. For example, I saw the custom action IncreaseSalary in the sample but the test code always used Ok such as the following:
https://github.com/OData/AspNetCoreOData/blob/ce38df9ebc73575e103aa73544a4cfbb6e9d5814/test/Microsoft.AspNetCore.OData.E2E.Tests/BoundOperation/BoundOperationController.cs#L345
Relevant code setup below
IEdmModel setup:
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
var cardEntitySet = builder.EntitySet<Card>("Card");
var pageEntitySet = builder.EntitySet<Page>("Page");
var cardAddPage = cardEntitySet.EntityType.Action(nameof(CardController.AddPage));
cardAddPage.Namespace = cardEntitySet.EntityType.Name;
cardAddPage.ReturnsFromEntitySet(pageEntitySet);
...
}
The controller implementation:
public class CardController : ODataController
{
[EnableQuery]
[HttpPost("api/v1/Card({key})/Card.AddPage")]
[HttpPost("api/v1/Card({key})/Card.AddPage()")]
public async Task<IActionResult> AddPage(int key)
{
var card = await DbContext.Card.Include(e => e.Pages).FirstOrDefaultAsync(e => e.Id == key);
if (card == null) return NotFound(key);
var page = new Page();
card.Pages.Add(page);
await DbContext.SaveChangesAsync();
// Using ODataController.Created below causes the InvalidOperationException
// return Created(page);
// Workaround:
return Ok(page);
}
}
The above custom action shows up as I would expect in the $metadata page (return type specified correctly to the right entityset) and in the debug $odata page (enabled via UseODataRouteDebug) as being correctly setup underneath the OData Endpoint Mapping table (as opposed to being listed under the Non-OData Endpoint Mapping table).
Version information
- net6.0 preview 3 (6.0.100-preview.3.21202.5)
- Microsoft.AspNetCore.OData 8.0.0-Nightly202105211212
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the custom Card.AddPage action using Created(page) and compare it with the Ok(page) workaround. Read the E2D bound-operation example in test/Microsoft.AspNetCore.OData.E2E.Tests/BoundOperation/BoundOperationController.cs around line 345, then trace the ODataController Created result and route metadata; done means the action returns successfully with the expected entity payload and OData query options.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100