Microsoft.OData.ODataException when returning a SingleResult from a function
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 505
- Forks
- 186
- PR merge metrics
- No merged PRs in 30d
Description
Here is an issue that seems to occur in the current version 8.0.0-preview (and also in the current master branch). It worked correctly in version 7.5.1.
I have a controller method that returns an single entity IQueryable<User>, because I would like to use it with expand:
[EnableQuery]
[HttpGet("current")]
public ActionResult<SingleResult<User>> Current()
{
var currentUser = dbContext.Users().Where(u => u.Id == _currentUser.Id);
return Ok(SingleResult.Create(currentUser));
}
It's defined in the EdmModel like this:
builder.EntityType<User>().Collection
.Function("Current")
.Returns<User>();
This throws an ODataException during serialization:
When writing a JSON response, a user model must be specified and the entity set and entity type must be passed to the ODataMessageWriter.CreateODataResourceWriter method or the ODataResourceSerializationInfo must be set on the ODataResource or ODataResourceSet that is being written.
Stacktrace:
at Microsoft.OData.ODataResourceTypeContext.ValidateAndReturn[T](T value)
at Microsoft.OData.ODataResourceTypeContext.get_NavigationSourceName()
at Microsoft.OData.ODataContextUrlInfo.Create(ODataResourceTypeContext typeContext, ODataVersion version, Boolean isSingle, ODataUri odataUri)
at Microsoft.OData.JsonLight.ODataJsonLightResourceSerializer.<>c__DisplayClass11_0.<WriteResourceContextUri>b__0()
at Microsoft.OData.JsonLight.ODataJsonLightSerializer.WriteContextUriProperty(ODataPayloadKind payloadKind, Func`1 contextUrlInfoGen, ODataContextUrlInfo parentContextUrlInfo, String propertyName)
at Microsoft.OData.JsonLight.ODataJsonLightResourceSerializer.WriteResourceContextUri(ODataResourceTypeContext typeContext, ODataContextUrlInfo parentContextUrlInfo)
at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource(ODataResource resource)
at Microsoft.OData.ODataWriterCore.<>c__DisplayClass121_0.<WriteStartResourceImplementation>b__0()
at Microsoft.OData.ODataWriterCore.InterceptException(Action action)
at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation(ODataResource resource)
at Microsoft.OData.ODataWriterCore.WriteStart(ODataResource resource)
at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.WriteResource(Object graph, ODataWriter writer, ODataSerializerContext writeContext, IEdmTypeReference expectedType) in C:\Users\..\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\Serialization\ODataResourceSerializer.cs:line 362
at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) in C:\Users\..\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\Serialization\ODataResourceSerializer.cs:line 85
at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) in C:\Users\..\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\Serialization\ODataResourceSerializer.cs:line 62
at Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatterHelper.WriteToStream(Type type, Object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, HttpRequest request, IHeaderDictionary requestHeaders, ODataSerializerProvider serializerProvider) in C:\Users\..\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataOutputFormatterHelper.cs:line 153
at Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) in C:\Users\..\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataOutputFormatter.cs:line 230
Notes:
- It works fine if I return the same result from a normal controller method without a special definition in the EdmModel, so SingleResult itself is not the problem:
[EnableQuery]
[HttpGet("{key}")]
public ActionResult<SingleResult<User>> Get(Guid key)
{
var currentUser = dbContext.Users().Where(u => u.Id == key);
return Ok(SingleResult.Create(currentUser));
}
- The exception also occurs when I rewrite the method like this:
[EnableQuery]
[HttpGet("current")]
public IActionResult Current()
{
var currentUser = dbContext.Users().Where(u => u.Id == _currentUser.Id).Single();
return Ok(currentUser);
}
- However it suddenly works if I remove the Single() call from the query:
var currentUser = dbContext.Users().Where(u => u.Id == _currentUser.Id);
- Defining the function like this also does not work. This was the previous definition that worked in 7.5.1:
builder.EntityType<User>().Collection
.Function("Current")
.ReturnsFromEntitySet<User>("Users");
So the combination of SingleResult with the function definition seems to be the reason for this Exception. Is this a bug or am I doing something wrong?
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 function endpoint with SingleResult and compare it with the working normal controller and the 7.5.1 behavior. Start in Formatter/Serialization/ODataResourceSerializer.cs around line 362, then trace ODataOutputFormatterHelper.cs and the OData resource type-context stack frames. Done means the function response serializes without the ODataException for both SingleResult and a single entity.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100