如何处理Json.Net解析中的错误

我正在使用Json.Net进行Json反序列化。 有时我读的Json字符串不正确(我无法修复,因为我不生成它)。 特别是,在一个特定的地方,应该有一个字符串,有时会有一个序列化的对象。 Json.Net然后抱怨,并不奇怪,找到一个预期字符串的对象。

我发现我可以通过在JsonSerializerSettings使用Error来拦截它,并通过设置ErrorContext.Handled使Json.Net忽略该问题。 但我想做更多。 如果我可以查看序列化对象,我可以弄清楚字符串应该是什么,并在理论上提供正确的答案。 在实践中,我无法想象我们如何做到这一点。 特别是在error handling程序中:

  • 如何访问解析器绊倒的字符串(注意,如果设置了ErrorContext.Handled ,解析器可以成功继续,因此它可以正确地确定问题字符串的开始和结束)?
  • 如何将正确的字符串提供给解析器,或者可以访问当前解析的对象,以便我可以手动设置该值?

[编辑]根据要求提供简化示例:

我要解析的错误的Json字符串:

 { "id": 2623, "name": { "a": 39, "b": 0.49053320637463277, "c": "cai5z+A=", "name": "22" }, "children": [ { "id": 3742, "name": { "a": 37, "b": 0.19319664789046936, "c": "Me/KKPY=", "name": "50" }, "children": [ { "id": 1551, "name": { "a": 47, "b": 0.6935373953047849, "c": "qkGkMwY=", "name": "9" }, "children": [] }, { "id": 4087, "name": { "a": 5, "b": 0.42905938319352427, "c": "VQ+yH6o=", "name": "84" }, "children": [] }, { "id": 614, "name": { "a": 19, "b": 0.7610801005554758, "c": "czjTK1s=", "name": "11" }, "children": [] } ] }, { "id": 3382, "name": { "a": 9, "b": 0.36416331043660793, "c": "lnoHrd0=", "name": "59" }, "children": [ { "id": 4354, "name": { "a": 17, "b": 0.8741648112769075, "c": "CD2i2I0=", "name": "24" }, "children": [] }, { "id": 2533, "name": { "a": 52, "b": 0.8839575992356788, "c": "BxFEzVI=", "name": "60" }, "children": [] }, { "id": 5733, "name": { "a": 4, "b": 0.7230552787534219, "c": "Un7lJGM=", "name": "30" }, "children": [] } ] }, { "id": 9614, "name": { "a": 81, "b": 0.4015882813379114, "c": "dKgyRZk=", "name": "63" }, "children": [ { "id": 7831, "name": { "a": 81, "b": 0.2784254314743101, "c": "xZur64o=", "name": "94" }, "children": [] }, { "id": 6293, "name": { "a": 73, "b": 0.32629523068959604, "c": "lMkosP4=", "name": "93" }, "children": [] }, { "id": 5253, "name": { "a": 13, "b": 0.19240453242901923, "c": "oOPZ3tA=", "name": "5" }, "children": [] } ] } ] } 

并在这里分类解析为:

 class Node { [JsonProperty] int id; [JsonProperty] string name; [JsonProperty] List children; } 

正如您所看到的,它需要一个字符串name但有时会错误地获取一个序列化对象(其中包含有问题的字符串作为成员)。 这只发生在一些JSON字符串中,而不是其他字符串中,所以我不能只改变Node的类定义来匹配。

[编辑2]根据我的API,“正确”的Json字符串将如下所示:

 { "id": 2623, "name": "22", "children": [ { "id": 3742, "name": "50", "children": [ { "id": 1551, "name": "9", "children": [] }, { "id": 4087, "name":"84", "children": [] }, ... 

正如您所看到的那样,尝试在事后检测到错误,然后从错误点重新分析将会出现问题。 幸运的是,您所描述的问题可以使用自定义JsonConverter以简单的方式解决。 我们的想法是让转换器将数据读入一个临时结构,该结构可以处理表单(对象或字符串),查询类型,然后从那里构造Node

这是转换器的代码:

 class NodeConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Node)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); Node node = new Node(); node.id = (int)jo["id"]; JToken name = jo["name"]; if (name.Type == JTokenType.String) { // The name is a string at the current level node.name = (string)name; } else { // The name is one level down inside an object node.name = (string)name["name"]; } node.children = jo["children"].ToObject>(serializer); return node; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

要使用转换器,请将[JsonConverter]属性添加到Node类中,如下所示:

 [JsonConverter(typeof(NodeConverter))] class Node { public int id { get; set; } public string name { get; set; } public List children { get; set; } } 

然后你可以正常反序列化:

 Node node = JsonConvert.DeserializeObject(json); 

这是一个完整的演示,展示了转换器的运行情况。 为了便于说明,我创建了一个新的JSON字符串,其中包含您在问题中描述的“好”和“坏”节点的组合。

 class Program { static void Main(string[] args) { string json = @" { ""id"": 2623, ""name"": { ""a"": 39, ""b"": 0.49053320637463277, ""c"": ""cai5z+A="", ""name"": ""22"" }, ""children"": [ { ""id"": 3741, ""name"": ""50"", ""children"": [ { ""id"": 1550, ""name"": ""9"", ""children"": [] }, { ""id"": 4088, ""name"": { ""a"": 5, ""b"": 0.42905938319352427, ""c"": ""VQ+yH6o="", ""name"": ""85"" }, ""children"": [] } ] }, { ""id"": 3742, ""name"": { ""a"": 37, ""b"": 0.19319664789046936, ""c"": ""Me/KKPY="", ""name"": ""51"" }, ""children"": [ { ""id"": 1551, ""name"": { ""a"": 47, ""b"": 0.6935373953047849, ""c"": ""qkGkMwY="", ""name"": ""10"" }, ""children"": [] }, { ""id"": 4087, ""name"": ""84"", ""children"": [] } ] } ] }"; Node node = JsonConvert.DeserializeObject(json); DumpNode(node, ""); } private static void DumpNode(Node node, string indent) { Console.WriteLine(indent + "id = " + node.id + ", name = " + node.name); foreach(Node child in node.children) { DumpNode(child, indent + " "); } } } 

输出:

 id = 2623, name = 22 id = 3741, name = 50 id = 1550, name = 9 id = 4088, name = 85 id = 3742, name = 51 id = 1551, name = 10 id = 4087, name = 84