AspNetCoreOData
AspNetCoreOData copied to clipboard
Invalid JSON returned 500 when 400 is expected
Assemblies affected Microsoft.AspNetCore.OData 9.1.1
Describe the bug A clear and concise description of what the bug is.
Reproduce steps Send invalid JSON to OData endpoint
Request/Response
POST /something HTTP/2
...
{"routes":{"Id":34,"Routes":[{"DID":"17772229192","TrunkId":40,"DisplayName":"~!@#$%^&*()_+{}[]:\":|;'\<>?,./"}]}}
=>
HTTP/2 500 Internal Server Error
2024/11/27 09:35:36.762|0020|Erro| [Microsoft.AspNetCore.Server.Kestrel] Connection id "0HN8EN6DSSIMU", Request id "0HN8EN6DSSIMU:00000002": An unhandled exception was thrown by the application.
Microsoft.OData.ODataException: Invalid JSON. An unrecognized escape sequence '\<' was found in a JSON string value.
at Microsoft.OData.Json.JsonReader.ParseStringPrimitiveValueAsync()
at Microsoft.OData.Json.JsonReader.GetValueAsync()
at Microsoft.OData.Json.BufferingJsonReader.ReadInternalAsync()
at Microsoft.OData.Json.ReorderingJsonReader.ReadPropertyNameAsync()
at Microsoft.OData.Json.ReorderingJsonReader.ProcessObjectValueAsync()
at Microsoft.OData.Json.BufferingJsonReader.ReadNextAndCheckForInStreamErrorAsync()
at Microsoft.OData.Json.BufferingJsonReader.ReadInternalAsync()
at Microsoft.OData.Json.ODataJsonDeserializer.ReadPayloadStartImplementationAsync(ODataPayloadKind payloadKind, PropertyAndAnnotationCollector propertyAndAnnotationCollector, Boolean isReadingNestedPayload, Boolean allowEmptyPayload)
at Microsoft.OData.Json.ODataJsonDeserializer.ReadPayloadStartAsync(ODataPayloadKind payloadKind, PropertyAndAnnotationCollector propertyAndAnnotationCollector, Boolean isReadingNestedPayload, Boolean allowEmptyPayload, IEdmNavigatio>
at Microsoft.OData.Json.ODataJsonParameterReader.ReadAtStartImplementationAsync()
at Microsoft.OData.ODataParameterReaderCoreAsync.ReadAsynchronously()
at Microsoft.OData.ODataParameterReaderCore.InterceptExceptionAsync[TResult](Func`2 action)
at Microsoft.AspNetCore.OData.Formatter.Deserialization.ODataActionPayloadDeserializer.ReadAsync(ODataMessageReader messageReader, Type type, ODataDeserializerContext readContext)
at Microsoft.AspNetCore.OData.Formatter.ODataBodyModelBinder.ReadODataBodyAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.OData.Formatter.ODataBodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BinderTypeModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object >
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location ---
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.<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.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
Expected behavior Return 400
It disappoints me a bit that OData has so many of these cases of poor error handling that either result in a 500, or do the opposite and ignore exceptions that should be 500 and return 200 instead...
It's honestly one of the things (out of a few) that makes the framework look unprofessional/unpolished.