OData / AspNetCoreOData

ASP.NET Core OData: A server library built upon ODataLib and ASP.NET Core
Other
454 stars 161 forks source link

Error in deserialization implementing the $expand option #1020

Closed JuanGoDev closed 1 year ago

JuanGoDev commented 1 year ago

OData Version Microsoft.AspNetCore.OData - 8.2.1 (.Net 6)

After upgrading the OData version to 8.2.1 I started to experience another error, which as far as I have been able to find out is related to the $expand option, I will tell you what is happening to me:

Example of OData paths with which I am experiencing error:

http://localhost:49350/odata/v1/categoryelements?$expand=category

https://localhost:49350/v1/odata/categoryelements?$expand=category,icon&$top=10

image

When generating the response to the OData query, the JSON values are generated incomplete, and therefore my API generates error when deserializing the response.

Among other paths in which $expand is used.

But the funny thing is that I had as a premise that this happened with my OData paths where I implemented $expand, but it didn't, for example the following OData path works for me:

https://localhost:49350/v1/odata/nodeconnections?$expand=SourceNode($select=name,%20isActive),DestinationNode($select=name,%20isActive),Algorithm&$select=nodeConnectionId,sourceNodeId,destinationNodeId,controlLimit,isActive,isTransfer,algorithmId,rowVersion&$top=10&$orderby=nodeConnectionId%20desc.

Keep in mind that in OData version 8.2.0 the $expand worked, after upgrading to version 8.2.1 it stopped working and generates these errors.

Example scenario 1

image

image

ERROR IN DESERIALIZATION

Unexpected end when deserializing object. Path 'value[0].elementId', line 1, position 135.
      Newtonsoft.Json.JsonSerializationException: Unexpected end when deserializing object. Path 'value[0].elementId', line 1, position 135.
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateJObject(JsonReader reader)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
donbecker commented 1 year ago

It appears I am also impacted by this.

I've confirmed that I only needed to revert to 8.2.0 to fix the issue.

xuzhg commented 1 year ago

@JuanGoDev @donbecker Would you please share a repro with us to dig more? The call stack looks weird to me since it's using Newtonsoft.JSON. Why does your codes call the Newtonsoft APIs?

JuanGoDev commented 1 year ago

@JuanGoDev @donbecker¿Podría compartir una reproducción con nosotros para profundizar más? La pila de llamadas me parece extraña ya que usa Newtonsoft.JSON. ¿Por qué sus códigos llaman a las API de Newtonsoft?

Once the response is returned from OData, later in the code the content of the response is used and deserialized, the value of the "api" parameter is the OData path, and as a response you get the JSON as I showed in the example scenario, the JSON is generated incomplete, therefore when deserializing it is not able to map it to the entity.

image

xuzhg commented 1 year ago

@JuanGoDev @donbecker¿Podría compartir una reproducción con nosotros para profundizar más? La pila de llamadas me parece extraña ya que usa Newtonsoft.JSON. ¿Por qué sus códigos llaman a las API de Newtonsoft?

Once the response is returned from OData, later in the code the content of the response is used and deserialized, the value of the "api" parameter is the OData path, and as a response you get the JSON as I showed in the example scenario, the JSON is generated incomplete, therefore when deserializing it is not able to map it to the entity.

image

@JuanGoDev Do you mind sharing your whole repro for me to dig more?

JuanGoDev commented 1 year ago

@JuanGoDev @donbecker¿Podría compartir una reproducción con nosotros para profundizar más? La pila de llamadas me parece extraña ya que usa Newtonsoft.JSON. ¿Por qué sus códigos llaman a las API de Newtonsoft?

Una vez que se devuelve la respuesta de OData, más adelante en el código, el contenido de la respuesta se usa y se deserializa, el valor del parámetro "api" es la ruta de OData y, como respuesta, obtiene el JSON como se muestra en el escenario de ejemplo. , el JSON se genera incompleto, por lo que al deserializarlo no se puede mapear a la entidad. imagen

@JuanGoDev¿Te importaría compartir toda tu reproducción para que investigue más?

Where do I share all the reproduction ?

JuanGoDev commented 1 year ago

@xuzhg If you need anything else let me know.

Filters.WebExceptionFilterAttribute[0]
      Unexpected end when deserializing object. Path 'value[0].elementId', line 1, position 135.
      Newtonsoft.Json.JsonSerializationException: Unexpected end when deserializing object. Path 'value[0].elementId', line 1, position 135.
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateJObject(JsonReader reader)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
         at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
         at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
         at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)
         at Extensions.DeserializeHttpContentAsync[T](HttpContent content) in Extensions.cs:line 232
         at ApiService.GetAsync[T](String api) in ApiService.cs:line 0
         at DataController.QueryAsync(String version, String path) in DataController.cs:line 56
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
         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>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
xuzhg commented 1 year ago

@JuanGoDev @donbecker¿Podría compartir una reproducción con nosotros para profundizar más? La pila de llamadas me parece extraña ya que usa Newtonsoft.JSON. ¿Por qué sus códigos llaman a las API de Newtonsoft?

Una vez que se devuelve la respuesta de OData, más adelante en el código, el contenido de la respuesta se usa y se deserializa, el valor del parámetro "api" es la ruta de OData y, como respuesta, obtiene el JSON como se muestra en el escenario de ejemplo. , el JSON se genera incompleto, por lo que al deserializarlo no se puede mapear a la entidad. imagen

@JuanGoDev¿Te importaría compartir toda tu reproducción para que investigue más?

Where do I share all the reproduction ?

@JuanGoDev Do you mind sharing it using a GitHub repository?

FridayPhil commented 1 year ago

I've also hit this problem, and to add info, I found that the $expand in 8.2.1 is only failing if the expand entity has nullable fields. It seems in the initialisation, it can't handle, but if I made all target fields nullable, was OK in 8.2.1, which is still wrong.

Reverted to 8.2.0 & working OK again.

xuzhg commented 1 year ago

@FridayPhil Would you please help try the latest nightly package?

FridayPhil commented 1 year ago

@FridayPhil Would you please help try the latest nightly package?

I just trued 8.3.1-Nightly202308161852 - Sorry, not fixed. My OData calls that include $expand=xyz, where xyz has nullable properties still fails. Reverting to 8.2.0, which worked OK.

xuzhg commented 1 year ago

@FridayPhil Would you please help try the latest nightly package?

I just trued 8.3.1-Nightly202308161852 - Sorry, not fixed. My OData calls that include $expand=xyz, where xyz has nullable properties still fails. Reverting to 8.2.0, which worked OK.

@FridayPhil The nightly version looks weird for me. Can You share more details for me to dig?

1) Your simple C# model classes 2) Your Model Builder Codes 3) Your Startup configuration 4) Your Simple Controller 5) Your Sample Data, with null value properties

Thanks.

xuzhg commented 1 year ago

@FridayPhil Also, would you please try this nightly: Microsoft.AspNetCore.OData.8.2.2-Nightly202308210623.nupkg

xuzhg commented 1 year ago

WebApplication1.zip

Any one can help me to make the attached as a repro?

FridayPhil commented 1 year ago

WebApplication1.zip

Any one can help me to make the attached as a repro?

Don't have a lot of time for this, but tried. I think your Zip is incomplete. sln is referring to 2nd project, which is not there.

xuzhg commented 1 year ago

WebApplication1.zip Any one can help me to make the attached as a repro?

Don't have a lot of time for this, but tried. I think your Zip is incomplete. sln is referring to 2nd project, which is not there.

I referred the source project. Please clone this repo and update the project reference. Let me know any other help?

JuanGoDev commented 1 year ago

Hello @xuzhg , tell me what has been done to solve the error that I am presenting ? do you know anything ?

ElizabethOkerio commented 1 year ago

@JuanGoDev do you have builder.EnableLowerCamelCase() enabled?

JuanGoDev commented 1 year ago

@JuanGoDev do you have builder.EnableLowerCamelCase() enabled?

Hello @ElizabethOkerio , if activated.

image

ElizabethOkerio commented 1 year ago

This fix https://github.com/OData/AspNetCoreOData/pull/1024 will fix this problem then.

ElizabethOkerio commented 1 year ago

@JuanGoDev can you try this with the latest release https://www.nuget.org/packages/Microsoft.AspNetCore.OData/8.2.2 and let's know whether it fixes your issue

JuanGoDev commented 1 year ago

@JuanGoDev can you try this with the latest release https://www.nuget.org/packages/Microsoft.AspNetCore.OData/8.2.2 and let's know whether it fixes your issue

Hello @ElizabethOkerio , I already tested with the new version of OData and indeed it works, thank you very much for the support.

FridayPhil commented 1 year ago

FYI, as of 8.2.2 still not fixed here. https://localhost:5001/odata/ScripTransactions?$top=10 works, https://localhost:5001/odata/ScripTransactions?$top=10&$expand=InstrumentE fails, with Exception: `Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.

System.InvalidOperationException: Nullable object must have a value. at lambda_method874(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext() at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSetAsync(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectInlineAsync(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectAsync(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatterHelper.WriteToStreamAsync(Type type, Object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, HttpRequest request, IHeaderDictionary requestHeaders, IODataSerializerProvider serializerProvider) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gLogged|22_0(ResourceInvoker invoker, IActionResult result) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gLogged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.gAwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Query.ODataQueryRequestMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Routing.ODataRouteDebugMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Warning: The response has already started, the error page middleware will not be executed. Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.

System.InvalidOperationException: Nullable object must have a value. at lambda_method874(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext() at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSetAsync(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectInlineAsync(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectAsync(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatterHelper.WriteToStreamAsync(Type type, Object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, HttpRequest request, IHeaderDictionary requestHeaders, IODataSerializerProvider serializerProvider) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gLogged|22_0(ResourceInvoker invoker, IActionResult result) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gLogged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.gAwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Query.ODataQueryRequestMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Routing.ODataRouteDebugMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Warning: The response has already started, the error page middleware will not be executed. Microsoft.AspNetCore.Server.Kestrel: Error: Connection id "0HMT9ODVH075O", Request id "0HMT9ODVH075O:00000001": An unhandled exception was thrown by the application.

System.InvalidOperationException: Nullable object must have a value. at lambda_method874(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.MoveNext() at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSetAsync(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectInlineAsync(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectAsync(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) at Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatterHelper.WriteToStreamAsync(Type type, Object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, HttpRequest request, IHeaderDictionary requestHeaders, IODataSerializerProvider serializerProvider) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Query.ODataQueryRequestMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.OData.Routing.ODataRouteDebugMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) at Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware.InvokeAsync(HttpContext context) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication1 application) The thread '.NET ThreadPool Worker' (0x64f0) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0x64cc) has exited with code 0 (0x0). The thread '[Thread Destroyed]' (0x472c) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0x4ca0) has exited with code 0 (0x0). The thread '.NET ThreadPool Worker' (0x4e48) has exited with code 0 (0x0). `

ElizabethOkerio commented 1 year ago

@FridayPhil can you share a repro.. Your model classes and your model.

JuanGoDev commented 1 year ago

@FridayPhil can you share a repro.. Your model classes and your model.

Hi @ElizabethOkerio , I have the sad news... yesterday I was testing and it fixed the error on the screen where I reported this bug, but another error came up also related to the $expand 😞...

JuanGoDev commented 1 year ago

@FridayPhil can you share a repro.. Your model classes and your model.

Hi @ElizabethOkerio , I have the sad news... yesterday I was testing and it fixed the error on the screen where I reported this bug, but another error came up also related to the $expand 😞...

Hello @ElizabethOkerio I am sorry, doing a more detailed analysis, I realize that the error is not of $expand, the error is that I have an object type property called Algorithm, and it generates the following error:

Property in my class NodeConnection:

public virtual Algorithm Algorithm { get; set; }

Error:

 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.InvalidOperationException: Nullable object must have a value.
   at lambda_method598(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at Microsoft.AspNetCore.OData.Query.Container.TruncatedCollection`1..ctor(IQueryable`1 source, Int32 pageSize, Boolean parameterize)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.LimitResults[T](IQueryable`1 queryable, Int32 limit, Boolean parameterize, Boolean& resultsLimited)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.LimitResults(IQueryable queryable, Int32 limit, Boolean parameterize, Boolean& resultsLimited)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplyPaging(IQueryable result, ODataQuerySettings querySettings)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   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__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.RedirectToIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I don't understand why in version 8.2.0 it works and in version 8.2.2 it doesn't, is it due to some change ? should I make some adjustment for that property ?

Endpoint:

 https://localhost:44387/odata/v1/nodeconnections?$expand=SourceNode($select=name,%20isActive),DestinationNode($select=name,%20isActive),Algorithm&$select=nodeConnectionId,sourceNodeId,destinationNodeId,controlLimit,isActive,isTransfer,algorithmId,rowVersion&$top=1&$orderby=nodeConnectionId%20desc

Results with OData 8.2.0 (Successful):

{
    "@odata.context": "https://localhost:44387/odata/v1/$metadata#NodeConnections(nodeConnectionId,sourceNodeId,destinationNodeId,controlLimit,isActive,isTransfer,algorithmId,rowVersion,sourceNode(name,isActive),destinationNode(name,isActive),algorithm())",
    "value": [
        {
            "nodeConnectionId": 42109,
            "sourceNodeId": 91727,
            "destinationNodeId": 92606,
            "isActive": true,
            "controlLimit": null,
            "isTransfer": false,
            "algorithmId": null,
            "rowVersion": "AAAAAAAUV8U=",
            "sourceNode": {
                "name": "NULO M4",
                "isActive": true
            },
            "destinationNode": {
                "name": "IG_QA_NODOC_TRAN_MD10",
                "isActive": true
            },
            "algorithm": null
        }
     ]
}

Results with OData 8.2.2 (Error):

 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.InvalidOperationException: Nullable object must have a value.
   at lambda_method598(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at Microsoft.AspNetCore.OData.Query.Container.TruncatedCollection`1..ctor(IQueryable`1 source, Int32 pageSize, Boolean parameterize)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.LimitResults[T](IQueryable`1 queryable, Int32 limit, Boolean parameterize, Boolean& resultsLimited)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.LimitResults(IQueryable queryable, Int32 limit, Boolean parameterize, Boolean& resultsLimited)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplyPaging(IQueryable result, ODataQuerySettings querySettings)
   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   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__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.RedirectToIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Why did you allow null values in the algorithm property before and not now?...

Please help me, thank you!

FridayPhil commented 1 year ago

I'm sorry, I don't have the opportunity to extract out a sendable version from our project at this time, but Juan's behaviour seems very similar failure to mine. Mine fails if the $expand entity has nullable properties (which are null), but this is normal. As per Juan, 8.2.0 works fine.

ElizabethOkerio commented 1 year ago

Ok. we are looking into this.

ElizabethOkerio commented 1 year ago

@JuanGoDev and @FridayPhil. Try this with the latest release https://www.nuget.org/packages/Microsoft.AspNetCore.OData/8.2.3 and let's know if it fixes your issue.

FridayPhil commented 1 year ago

Initial indications look good. My reported problem seems to be gone. Will keep testing & let you know if I find anything wrong.

JuanGoDev commented 1 year ago

@JuanGoDevy@FridayPhil. Pruebe esto con la última versión https://www.nuget.org/packages/Microsoft.AspNetCore.OData/8.2.3 y averigüemos si soluciona su problema.

Hi @ElizabethOkerio, with the new version of OData 8.2.3 it has been working well, however, my team and I have taken the decision to leave version 8.2.0 which is the most stable version for us so far. Thank you for your and your team's help, I will keep in touch with you in case something new happens.

xuzhg commented 1 year ago

@JuanGoDev @donbecker @FridayPhil Thanks for your time. Any comments help improve us to build better quality products for community. Please file new issues if you have more concerns/questions.