处理asp.net核心本地日期模型绑定异常

时间:2018-12-27 12:27:08

标签: c# asp.net-core model-binding nodatime

我的意图是在消息有效内容格式或数据无效时从服务器返回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-Client。

可能的原因?:

  • 在NodaTime反序列化过程中,JsonInputFormatter似乎利用了jsonSerializer.Error和prevnt抛出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

0 个答案:

没有答案
相关问题