【问题标题】:Handle multiple binding errors from ModelBindingException in NancyFX when binding to JSON in Request.Body当绑定到 Request.Body 中的 JSON 时,处理来自 NancyFX 中的 ModelBindingException 的多个绑定错误
【发布时间】:2017-01-17 22:52:00
【问题描述】:

我有一个 post 路由,它在请求正文中接受一些 JSON 有效负载。

Post["/myroute/}"] = _ =>
{
    try
    {
       var model = this.Bind<MyModel>();
    }
    catch (ModelBindingException e)  
    {
       //PropertyBindException list is empty here, 
       //so only the first exception can be handled...
    }
}

如果有多个无效数据类型(即,如果在 MyModel 中定义了多个 int 属性,并且用户为这些属性发布了字符串),我想传回这些错误的一个很好的列表,类似于如何使用 ModelState普通 ASP.NET MVC 应用程序中的字典。

在尝试将请求正文中的 JSON 有效负载绑定到 NancyFX 中的模型时,如何完成此类异常处理?

更新:

在这里查看 Nancy 源中的 DefaultBinder: https://github.com/sloncho/Nancy/blob/master/src/Nancy/ModelBinding/DefaultBinder.cs

我看到的问题是在这个块中:

        try
        {
            var bodyDeserializedModel = this.DeserializeRequestBody(bindingContext);
            if (bodyDeserializedModel != null)
            {
                UpdateModelWithDeserializedModel(bodyDeserializedModel, bindingContext);
            }
        }
        catch (Exception exception)
        {
            if (!bindingContext.Configuration.IgnoreErrors)
            {
                throw new ModelBindingException(modelType, innerException: exception);
            }
        }

Deserialize 调用似乎是“全有或全无”,它由普通异常处理,而不是 ModelBindException,所以我在这里也看不到任何 PropertyBindExceptions。

我是否需要为此实现一些自定义的东西...?

【问题讨论】:

  • 我遇到了同样的问题。 stackoverflow.com/questions/26107656/… 展示了一种忽略单个解析错误的简单方法,您甚至可以单独捕获它们。因此,在我看来,您需要使用此方法实现自己的 IBodyDeserializer。

标签: c# json model-binding nancy


【解决方案1】:

添加您自己的自定义正文序列化程序,使用 newtonsoft 忽略错误:

 public class CustomBodyDeserializer : IBodyDeserializer
{
    private readonly MethodInfo deserializeMethod = typeof(JavaScriptSerializer).GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.Public);
    private readonly JsonConfiguration jsonConfiguration;
    private readonly GlobalizationConfiguration globalizationConfiguration;

    /// <summary>
    /// Initializes a new instance of the <see cref="JsonBodyDeserializer"/>,
    /// with the provided <paramref name="environment"/>.
    /// </summary>
    /// <param name="environment">An <see cref="INancyEnvironment"/> instance.</param>
    public CustomBodyDeserializer(INancyEnvironment environment)
    {
        this.jsonConfiguration = environment.GetValue<JsonConfiguration>();
        this.globalizationConfiguration = environment.GetValue<GlobalizationConfiguration>();
    }

    /// <summary>
    /// Whether the deserializer can deserialize the content type
    /// </summary>
    /// <param name="mediaRange">Content type to deserialize</param>
    /// <param name="context">Current <see cref="BindingContext"/>.</param>
    /// <returns>True if supported, false otherwise</returns>
    public bool CanDeserialize(MediaRange mediaRange, BindingContext context)
    {
        return Json.IsJsonContentType(mediaRange);
    }

    /// <summary>
    /// Deserialize the request body to a model
    /// </summary>
    /// <param name="mediaRange">Content type to deserialize</param>
    /// <param name="bodyStream">Request body stream</param>
    /// <param name="context">Current context</param>
    /// <returns>Model instance</returns>
    public object Deserialize(MediaRange mediaRange, Stream bodyStream, BindingContext context)
    {            

        //var serializer = new JavaScriptSerializer(this.jsonConfiguration, this.globalizationConfiguration);

        //serializer.RegisterConverters(this.jsonConfiguration.Converters, this.jsonConfiguration.PrimitiveConverters);

        if (bodyStream.CanSeek)
        {
            bodyStream.Position = 0;
        }

        string bodyText;
        using (var bodyReader = new StreamReader(bodyStream))
        {
            bodyText = bodyReader.ReadToEnd();
        }

       // var genericDeserializeMethod = this.deserializeMethod.MakeGenericMethod(context.DestinationType);

       // var deserializedObject = genericDeserializeMethod.Invoke(serializer, new object[] { bodyText });


        object deserializedObject = JsonConvert.DeserializeObject(bodyText, context.DestinationType, new JsonSerializerSettings
        {
            Error = HandleDeserializationError
        });

        return deserializedObject;
    }

    public void HandleDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorArgs)
    {
        string currentError = errorArgs.ErrorContext.Error.Message;
        errorArgs.ErrorContext.Handled = true;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 2017-01-29
    • 1970-01-01
    • 2012-07-28
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多