Newtonsoft JSON.NET 反序列化错误
Posted
技术标签:
【中文标题】Newtonsoft JSON.NET 反序列化错误【英文标题】:Newtonsoft JSON.NET Deserialization error 【发布时间】:2015-02-16 13:03:36 【问题描述】:我在单个文件中有一堆长的 json 输出。我需要读取这些文件并将它们反序列化为最初生成 json 的实体(我可以访问原始实体)。每个文件都有通过序列化 IEnumerable<Response<MyEntity>>
类型的对象生成的 json 输出。
我在尝试反序列化时遇到异常,但我不明白为什么。这是我反序列化的尝试:
List<string> jsonOutputStrings;
// Read json from files and populate jsonOutputStrings list
List<Response<MyEntity>> apiResponses = new List<Response<MyEntity>>();
foreach (string json in jsonOutputStrings)
apiResponses.AddRange(JsonConvert.DeserializeObject<List<Response<MyEntity>>>(json, new JsonSerializerSettings TypeNameHandling = TypeNameHandling.All ).ToList());
我还尝试反序列化为 IEnumerable 而不是列表:
apiResponses.AddRange(JsonConvert.DeserializeObject<IEnumerable<Response<MyEntity>>>(json, new JsonSerializerSettings TypeNameHandling = TypeNameHandling.All ).ToList());
我得到以下异常:
类型的第一次机会异常 'Newtonsoft.Json.JsonSerializationException' 发生在 Newtonsoft.Json.dll
附加信息:无法创建和填充列表类型 System.Linq.Enumerable+WhereSelectListIterator`2[Entities.Requirement,Entities.RequirementEntity]。 小路 '$values[0].ReturnedEntity.Summaries.$values[0].Requirements.$values', 第 1 行,位置 715。
整个 json 太长,无法发布(并且还包含一些机密数据),但我确实在 json 中找到了一个位置:
"Requirements":"$id":"7","$type":"System.Linq.Enumerable+WhereSelectListIterator`2[[Entities.Requirement, Entities],[Entities.RequirementEntity, API.Entities]], System.Core","$values":[...]
在我尝试反序列化的实体(与最初序列化的实体相同)中,Requirements
的类型为 IEnumerable<Entities.RequirementEntity>
。
MyEntity
的序列化如何工作对我来说没有意义,但反序列化为相同类型却没有。我该如何解决这个问题?
【问题讨论】:
您是否尝试反序列化为IEnumerable<ApiResponse<StudentReportApiEntity>>>
?
是的,这就是我首先做的。我仍然得到同样的错误。 IEnumerable<Entities.RequirementEntity>
属性似乎有问题,该属性嵌套在父实体中的多个级别,但我不知道为什么......
这可能是一个愚蠢的问题,但是您要反序列化的 List 类型的命名空间是什么? System.Collections...?
如果您从序列化结果中排除该类型,那么它对您有用吗? (检查TypeNameHandling
设置)
@AndrewWhitaker - 谢谢!当我在反序列化时将 TypeNameHandling 设置为 None 时,它起作用了。
【参考方案1】:
您必须浏览 Response<>
和 MyEntity
并查看集合是如何初始化的。这告诉我们,某个类中的一个集合是使用 linq 中的 Where
方法创建的。您可以通过执行以下代码来重现此错误:
class MyEntity
public MyEntity()
Data = new List<string>().Where(x => true);
public IEnumerable<string> Data get; set;
class Program
static void Main(string[] args)
string data = @"[""Data"":[""a"",""b""]]";
var j = JsonConvert.DeserializeObject<IEnumerable<MyEntity>>(data);
另一种可能性是在 json 中有元数据。那么你有两个解决方案:
将TypeNameHandling
设置为TypeNameHandling.None
(正如评论中提到的那样);
将字符串中的不工作类型替换为工作类型
当您拥有IEnumerable<BaseType>
并且该列表包含BaseType
的子类型时,使用TypeNameHandling.None
可能会导致错误的反序列化。
在这种情况下,您应该选择第二种选择。基本上你应该替换任何不反序列化的类型,例如用List
替换它。
示例代码:
class MyEntity
public IEnumerable<string> Data get; set;
class Program
static void Main(string[] args)
IList<MyEntity> entities = new MyEntity[]
new MyEntity Data = new [] "1", "2" .Where(x => x != string.Empty) ,
new MyEntity Data = new [] "A", "B" .AsQueryable().Where(x => x != string.Empty) ,
new MyEntity Data = new List<string> "A", "B" ,
;
string data = JsonConvert.SerializeObject(entities, Formatting.Indented, new JsonSerializerSettings TypeNameHandling = TypeNameHandling.All );
data = Regex.Replace(data, "\"\\$type\":\\s+\"System.Linq.Enumerable\\+WhereArrayIterator(.+?), System.Core\",", "\"$type\": \"System.Collections.Generic.List$1, mscorlib\",", RegexOptions.Singleline);
var j = JsonConvert.DeserializeObject<IEnumerable<MyEntity>>(data, new JsonSerializerSettings TypeNameHandling = TypeNameHandling.All );
【讨论】:
谢谢,这很有帮助。很可能这就是正在发生的事情,我将不得不寻找它以防止将来发生这种情况。我现在遇到的问题是,我们已经有大约 1000 个包含数月数据的这些 json 文件,而且我们没有办法重新生成它们。有什么方法可以操纵 json 字符串/json 文件,使它们看起来像你描述的那样不是用 linq 创建的集合,以便我可以反序列化它们? 这个问题与json本身无关,与.net类有关。在反序列化集合时,反序列化器会尝试向其中添加元素。如果集合是只读的(例如数组或 linq 结果),则抛出异常。您应该在代码中搜索集合初始值设定项。例如,如果您从我的代码中删除 'where',它将起作用。 在我的情况下,我在列表中没有导致问题的集合初始化程序,但是当最初创建和序列化 json 时,linq 用于填充 IEnumerable(不是作为类的一部分,只是使用二传手)。 我现在看到你有元数据,这会导致问题。您也可以不将TypeNameHandling
设置为None
,而是将字符串中不支持的类型名称替换为支持的类型名称。我在答案中添加了示例代码。【参考方案2】:
序列化实体中是否有 Linq 结果?也许定义为 IEnumerable 并填充了 Linq Where 结果?看来这就是你的问题所在。 在序列化之前,您应该将其转换为 List 或 Array。
【讨论】:
谢谢,这很有帮助。很可能这就是正在发生的事情,我将不得不寻找它以防止将来发生这种情况。我现在遇到的问题是,我们已经有大约 1000 个包含数月数据的这些 json 文件,而且我们没有办法重新生成它们。有什么方法可以操纵 json 字符串/json 文件,使它们看起来像你描述的那样不是用 linq 创建的集合,以便我可以反序列化它们?以上是关于Newtonsoft JSON.NET 反序列化错误的主要内容,如果未能解决你的问题,请参考以下文章
.Net使用Newtonsoft.Json.dll(JSON.NET)对象序列化成json反序列化json示例教程
一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;
如何使用 NewtonSoft Json.Net 将 Json 字典反序列化为平面类