Я намеревался вернуть код состояния 400 с сервера, когда полезная нагрузка сообщения имеет недопустимый формат или данные.Однако при отправке значения xyz123 для поля даты сервер возвращает код состояния 500.Исключение:
NodaTime.Text.UnparsableValueException: The value string does not match the required number from the format string "uuuu". Value being parsed: '^xyz123'. (^ indicates error position.)
at NodaTime.Text.ParseResult`1.GetValueOrThrow() in C:\Users\jon\Test\Projects\nodatime\build\tzdbupdate\tmp-2.4\nodatime\src\NodaTime\Text\ParseResult.cs:line 81
at NodaTime.Serialization.JsonNet.NodaConverterBase`1.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 2159
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 1032
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 2386
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Formatters.JsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
Я ожидал, что исключение будет перехвачено и помещено в словарь ModelState.Есть ли способ внедрить это поведение (то есть перехват исключений) в JsonInputFormatter или BodyModelBinder, чтобы добавить их в ModelState вместо того, чтобы они нарушали привязку модели?
В качестве обходного пути я использую промежуточное программное обеспечение для обработки ошибок дляпоймать FormatException.На данный момент у меня, однако, больше нет контекстной информации, такой как JPATH, чтобы помочь пользователю или UI-клиенту.
Возможные причины?:
- Ошибка десериализации NodaTime, JsonInputFormatter, кажется, используетjsonSerializer.Error и prent throwing JsonException (но используются FormatException)
- Ошибка в десериализации ядра asp.net, должна обрабатывать FormatException
- Неправильная конфигурация на моей стороне
Модульный тест для воспроизведения поведения
public class ModelBindingErrorTest
{
private class ModelBindingErrorStartup
{
public void ConfigureServices(IServiceCollection services)
{
var mvcBuilder = services.AddMvc();
services.Configure<MvcJsonOptions>(options => options.SerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb));
//var mvcBuilder = services.AddMvcCore();
//mvcBuilder.AddJsonFormatters(jsonSerializerSettings => jsonSerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb));
mvcBuilder.AddApplicationPart(typeof(ModelBindingErrorStartup).Assembly);
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
[Fact]
public async Task Test()
{
var message = "The value string does not match the required number from the format string \"uuuu\". Value being parsed: \'^123xyz\'. (^ indicates error position.)";
try
{
var client = new TestServer(new WebHostBuilder().UseStartup<ModelBindingErrorStartup>()).CreateClient();
var response = await client.PostAsync(new Uri("/MainController/LocalDate", UriKind.Relative), new StringContent("{'Birthday':'123xyz'}", Encoding.UTF8, MediaTypeNames.Application.Json));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(message, body);
}
catch (UnparsableValueException e)
{
Assert.Equal(message, e.Message);
// The Test Fails Here
Assert.False(true);
}
}
}
[Route("/MainController")]
public class MainController : Controller
{
[HttpPost("LocalDate")]
public object LocalDate([FromBody]Model model)
{
return ModelState["Birthday"].Errors[0].Exception.Message;
}
}
public class Model
{
public LocalDate Birthday { get; set; }
}
Использованные пакеты
- Microsoft.AspNetCore.TestHost 2.2.0
- Microsoft.NET.Test.Sdk 15.9.0
- Newtonsoft.Json 12.0.1
- NodaTime 2.4.2
- NodaTime.Serialization.JsonNet 2.0.0
- Swashbuckle.NodaTime.AspNetCore 2.0.0
- xunit 2.4.1
- xunit.runner.visualstudio 2.4.1