【问题标题】:Handling Error in NewtonSoft Deserialization doesn't work处理 NewtonSoft 反序列化中的错误不起作用
【发布时间】:2018-10-12 09:43:26
【问题描述】:

我正在尝试处理反序列化错误,但即使我能够访问错误处理函数并将 Handled 属性设置为 true,也会将错误抛出到主函数。

型号:

public class PriceValidity
{
    public Date EndDate { get; set; }

    public Date StartDate { get; set; }

    [OnError]
    internal void OnError(StreamingContext context, ErrorContext errorContext)
    {
        errorContext.Handled = true;
    }
}

public class Date
{
    [JsonProperty("$date")]
    public DateTime Value { get; set; }
}

调用反序列化器:

private void ParseMessage<T>(string message) where T: new()
{
    var result = new T();
    var jsonSerializer = new Newtonsoft.Json.JsonSerializer();

    using (var reader = new StringReader(message))
    using (var jsonReader = new JsonTextReader(reader))
    {
        result = jsonSerializer.Deserialize<T>(jsonReader);
    };
}

JSON:

{  
   "StartDate":{  
      "$date":"2018-05-07T00:00:00.000Z"
   },
   "EndDate":{  
      "$date":{  
         "$numberLong":"253402214400000"
      }
   }
}

错误:

解析值后遇到意外字符::。路径'EndDate.$date',

我也不想处理 $numberLong 场景,而只是跳过它。

【问题讨论】:

  • 看看newtonsoft.com/json/help/html/SerializationErrorHandling.htm,了解如何正确使用OnError
  • @ChetanRanpariya - 我在该问题中找不到与您链接的文档不同的任何内容。你能帮忙吗?
  • 在文档中写道:“在此示例中,当未设置任何角色时,访问 Roles 属性将引发异常。HandleError 方法将在将角色序列化为已处理并允许 Json.NET 时设置错误继续序列化课程。”因此,如果我很好地理解了将 Handled 设置为 true 之后,应该进一步反序列化。还是我错了?
  • 我的建议是使用第一种方法,将 OnError 用作 JsonSerializerSettings 的一部分,而不是在实体类本身中使用 OnError。当实体类本身抛出异常变化时,在实体类中使用OnError 很有用,正如我共享的链接中PersonError 类的Roles 属性所解释的那样。对于 OP 的这个问题,NewtonSoft 库会引发异常...应该通过将OnError 作为JsonSerializerSettings 的一部分来处理。
  • 试图重现用例。 dotnetfiddle.net/HEh4qT 类内部的 OnError 中处理的错误和 JSON 序列化错误中处理的错误是不同的。因此,即使在类内部处理了一个错误,库也会抛出另一个错误..

标签: c# json.net


【解决方案1】:

不是答案,而是解决方法:将错误处理移至序列化程序选项:

    private T ParseMessage<T>(string message) where T : new() => 
        JsonConvert.DeserializeObject<T>(message, new JsonSerializerSettings
    {
        Error = (object sender, ErrorEventArgs args) => { args.ErrorContext.Handled = true; }
    });

来自 Chetan Ranpariya 的评论:

当实体类本身抛出异常变化时,在实体类中设置 OnError 非常有用,如此处对 PersonError 类的 Roles 属性的解释:https://www.newtonsoft.com/json/help/html/SerializationErrorHandling.htm

【讨论】:

  • 不幸的是它不能解决问题。目前我没有获得异常,但在这种情况下结果为空。所以对我来说,它看起来像 newtonsoft 中的错误...... :(
【解决方案2】:

终于找到了解决办法。 为了处理这种情况,我不得不创建 Json 转换器。

public class JMSDateTimeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            JToken token = JToken.Load(reader);

            if (token.Type == JTokenType.Object && GetAllChildresnCount(token) == 2)
            {
                return token.ToObject(objectType);
            }
            else
            {
                return null;
            }
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
        }
    }

    private int GetAllChildresnCount(JToken token)
    {
        var container = token as JContainer;

        if (container == null)
        {
            return 0;
        }

        var count = container.Count;

        foreach (JToken subToken in container)
        {
           count += GetAllChildresnCount(subToken);
        }

        return count;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

现在可以正常工作了。

【讨论】:

  • 使用自定义 JsonConverter 是一个很好的解决方案,因为 1) JSON 文件语法中的错误(例如,截断的文件)仍然会通过调用 JToken.Load(reader) 抛出,而反序列化中的错误不会; 2) Json.NET 中的内置错误处理被 Newtonsoft 声明为very flakey。如果您不想实现WriteJson(),可以覆盖CanWrite 并返回false,请参阅How to use default serialization in a custom JsonConverter
猜你喜欢
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
相关资源
最近更新 更多