【问题标题】:Newtonsoft.Json v11 - DeserializeObject throws JsonReaderExceptionNewtonsoft.Json v11 - DeserializeObject 抛出 JsonReaderException
【发布时间】:2018-03-01 17:23:42
【问题描述】:

我们已将 Newtonsoft.Json 从 10.0.3 升级到 11.0.1,之前运行的代码不再运行。

我们有以下 JSON:

[{"mail-type":"registration","response":"250 OK id=1UjnNr-gdf-C0 ","invoice-id":,"email":"testuser08@test.com"}]

我们调用以下方法:

var events = JsonConvert.DeserializeObject<Event[]>(jsonEvents);

这在 10.0.3 上运行良好,但在 11.0.1 上却不行。在这个版本中会抛出以下异常:

抛出异常:'Newtonsoft.Json.JsonReaderException' in Newtonsoft.Json.dll

附加信息:未定义的令牌不是有效的 System.Nullable`1[System.Int64]。路径“[0].invoice-id”,第 1 行。

我尝试将以下选项传递给DeserializeObject

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    MissingMemberHandling = MissingMemberHandling.Ignore
};

但仍然是同样的错误。必须进行哪些更改才能使其在 11.0.1 上运行。我担心我们无法容纳 JSON 输出,因为它来自第三方 API。

【问题讨论】:

  • 不确定具体发生了什么变化或原因,但您的 JSON 格式不正确。上传到jsonlint.com,你会看到如下错误:Error: Parse error on line 4: ...0 ", "invoice-id": ,Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got ','。 IE。 "invoice-id": , 属性不是格式良好的 JSON 属性。
  • @dbc 谢谢,我知道这一点。不幸的是,我无法创建这个 JSON,我需要解析它。不管怎样,以前的版本都可以反序列化,所以新版本也必须有一些东西来完成它。
  • 我认为它是:以前的版本有一个错误,允许解析格式错误的 json,就像你的一样。在较新的版本中,此错误已修复。所以我不明白为什么“在新版本中也必须有一些东西来完成它”。
  • @Evk 我想是的。但正如我所说,这个无效的 JSON 不是在我们的应用程序中创建的,但我们需要处理它。所以找到一种方法来处理它会很棒(例如编写自定义解析器或在选项中设置一些属性以忽略此类无效数据)
  • 看起来更改记录在 release notes 中:修复 - 修复了读取 undefined for nullable long 时不会出错的问题。我刚刚测试了 Json.NET 10.0,似乎使用int? 作为发票 ID 会导致异常,但使用 long? 作为发票 ID 会导致空值。在 11.0 中,int?long? 都抛出异常。

标签: c# json json.net


【解决方案1】:

您的 JSON 示例格式不正确。如果我将您的 JSON 上传到 https://jsonlint.com/,则会生成以下错误:

Error: Parse error on line 4:
...0 ",   "invoice-id": , "email": "testuse
----------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got ','

有问题的行如下:

"invoice-id": ,

根据JSON standard:, 之间需要有一个值。但是,为什么这在 Json.NET 10.0 中有效?显然这是一个错误,已修复。根据11.0.1 release notes

修复 - 修复了读取 undefined for nullable long

时不会出错的问题

因此,如果我们假设您的 Event 类型如下所示:

public partial class Event
{
    [JsonProperty("invoice-id")]
    public long? InvoiceId { get; set; }

    // Other properties as required
}

然后在 10.0 中,您的 JSON 可以使用此类型成功反序列化,但在 11.0 中则不能。但是,如果我们将InvoiceId 更改为int?

public partial class Event
{
    [JsonProperty("invoice-id")]
    public int? InvoiceId { get; set; }

    // Other properties as required
}

这两个版本都失败了。因此,修复似乎是一致地处理int?long?

理想情况下,您应该要求向您发送此类 JSON 的人对其进行修复,使其格式符合 http://www.json.org/RFC 8259 的定义。如果您仍然需要以与 Json.NET 10.0 相同的方式解析此类 JSON,您可以引入TolerantNullableLongConverter,如下所示:

public class TolerantNullableLongConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(long?);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        if (reader.TokenType == JsonToken.Undefined)
            return null;
        if (reader.Value is long)
            return reader.Value;
        // string or int or decimal or ...
        return serializer.Deserialize<long>(reader);
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

并将其应用于您的类型,如下所示:

public partial class Event
{
    [JsonProperty("invoice-id")]
    [JsonConverter(typeof(TolerantNullableLongConverter))]
    public long? InvoiceId { get; set; }

    // Other properties as required
}

【讨论】:

    【解决方案2】:

    您可以使用自定义转换器实现解决方法:

    internal class NullableLongFixupConverter : JsonConverter {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
            writer.WriteValue(value);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
            // if token undefined - return null
            if (reader.TokenType == JsonToken.Undefined)
                return null;
            // otherwise - value
            return (long?) reader.Value;
        }
    
        public override bool CanConvert(Type objectType) {
            return objectType == typeof(long?);
        }
    }
    

    然后你可以用它来装饰属性:

    class Event {
        [JsonProperty("invoice-id")]        
        [JsonConverter(typeof(NullableLongFixupConverter))]
        public long? InvoiceId { get; set; }
    }
    

    或全局注册(只会为long?类型的属性调用):

    JsonConvert.DefaultSettings = () =>
    {
        var s = new JsonSerializerSettings();                    
        s.Converters.Add(new NullableLongFixupConverter());
        return s;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多