-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Closed
Labels
DoneThis issue has been fixedThis issue has been fixedarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesenhancementThis issue represents an ask for new feature or an enhancement to an existing oneThis issue represents an ask for new feature or an enhancement to an existing one
Milestone
Description
Describe the bug
NewtonsoftJsonInputFormatter does not handle malformed input at least for DateTime fields.
So, malformed request results in unhandled exception and http 500 response.
To Reproduce
Net core 3, controller:
public class SomeRequest
{
[Required]
public DateTime RequestData { get; set; }
}
public class SomeResponse
{
[Required]
public DateTime RequestData { get; set; }
}
[ApiController]
[Route("testCalls")]
public class TestCallsController : ControllerBase
{
[HttpPost]
[Route("echo")]
[Consumes("application/json")]
public SomeResponse EchoPost([Required] SomeRequest request) // (1)
{
return new SomeResponse
{
RequestData = request.RequestData
};
}
}setup:
services
.AddControllers()
.ConfigureApiBehaviorOptions(
o =>
{
o.InvalidModelStateResponseFactory = c =>
{
Debugger.Break(); // Did not get called
return new BadRequestObjectResult(c.ModelState);
};
})
.AddNewtonsoftJson();UPD, the
.AddNewtonsoftJson(
options =>
{
options.AllowInputFormatterExceptionMessages = true;
});does not help.
request:
curl -X POST "https://localhost:44310/testCalls/echo" -H "accept: text/plain" -H "Content-Type: application/json" -d "{\"requestData\":\"invalidDate\"}"
Actual behavior
http 500, exception stack:
System.FormatException: The string 'invalidDate' was not recognized as a valid DateTime. There is an unknown word starting at index '0'.
at System.DateTimeParse.Parse(ReadOnlySpan`1 s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
at System.DateTime.Parse(String s, IFormatProvider provider, DateTimeStyles styles)
at Newtonsoft.Json.Converters.IsoDateTimeConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, 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)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
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.<InvokeNextResourceFilter>g__Awaited|24_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 where exception was thrown ---
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 Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Expected behavior
Invalid input should be handled by InvalidModelStateResponseFactory call (http 400, by default).
Additional context
As a hack the formatter may be replaced with any derived class, explanation:
// Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter
public virtual InputFormatterExceptionPolicy ExceptionPolicy
{
get
{
if (GetType() == typeof(NewtonsoftJsonInputFormatter))
{
return InputFormatterExceptionPolicy.MalformedInputExceptions;
}
return InputFormatterExceptionPolicy.AllExceptions; // FormatException will be handled too
}
}
Metadata
Metadata
Assignees
Labels
DoneThis issue has been fixedThis issue has been fixedarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesenhancementThis issue represents an ask for new feature or an enhancement to an existing oneThis issue represents an ask for new feature or an enhancement to an existing one