简体   繁体   English

Newtonsoft JSON.NET反序列化错误

[英]Newtonsoft JSON.NET Deserialization error

I am have a bunch of long json output in individual files. 我在单个文件中有一堆长json输出。 I need to read these files and deserialize them into the entities that originally generated the json (I have access to the original entities). 我需要读取这些文件并将它们反序列化为最初生成json的实体(我可以访问原始实体)。 Each file has the json output that was generated by serializing an object of type IEnumerable<Response<MyEntity>> . 每个文件都有通过序列化IEnumerable<Response<MyEntity>>类型的对象生成的json输出。

I am getting an exception when attempting to deserialize, but I don't understand why. 我试图反序列化时遇到异常,但我不明白为什么。 Here is my attempt to deserialize: 这是我尝试反序列化:

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());
}

I also tried deserializing to an IEnumerable instead of a list: 我也尝试反序列化到IEnumerable而不是列表:

apiResponses.AddRange(JsonConvert.DeserializeObject<IEnumerable<Response<MyEntity>>>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }).ToList());

I get the following exception: 我得到以下异常:

A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll Newtonsoft.Json.dll发生了'Newtonsoft.Json.JsonSerializationException'类型的第一次机会异常

Additional information: Cannot create and populate list type System.Linq.Enumerable+WhereSelectListIterator`2[Entities.Requirement,Entities.RequirementEntity]. 附加信息:无法创建和填充列表类型System.Linq.Enumerable + WhereSelectListIterator`2 [Entities.Requirement,Entities.RequirementEntity]。 Path '$values[0].ReturnedEntity.Summaries.$values[0].Requirements.$values', line 1, position 715. 路径'$ values [0] .ReturnedEntity.Summaries。$ values [0] .Requirements。$ values',line 1,position 715。

The entire json is too long to post (and also contains some confidential data) but I did find a place in the json that has this: 整个json太长而无法发布(并且还包含一些机密数据)但我确实在json中找到了一个包含此内容的地方:

"Requirements":{"$id":"7","$type":"System.Linq.Enumerable+WhereSelectListIterator`2[[Entities.Requirement, Entities],[Entities.RequirementEntity, API.Entities]], System.Core","$values":[...]}

In the entity that I'm trying to deserialize into (same one that was originally serialized), Requirements is of type IEnumerable<Entities.RequirementEntity> . 在我尝试反序列化的实体(最初序列化的IEnumerable<Entities.RequirementEntity> )中, Requirements的类型为IEnumerable<Entities.RequirementEntity>

It doesn't make sense to me how serialization from MyEntity works but deserializing to the same type doesn't. 对我来说, MyEntity序列化是如何工作的,但反序列化到同一类型却没有意义。 How do I solve this problem? 我该如何解决这个问题?

You must browse through Response<> and MyEntity and see how collections are initialized. 您必须浏览Response<>MyEntity并查看集合的初始化方式。 This tells us that one of the collections in some class is created using Where method from linq. 这告诉我们某些类中的一个集合是使用linq中的Where方法创建的。 You can reproduce this error by executing this code: 您可以通过执行以下代码重现此错误:

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);
    }
}

Another possibility is to have metadata in json. 另一种可能性是在json中使用元数据。 Then you have 2 solutions: 那么你有2个解决方案:

  • Set TypeNameHandling to TypeNameHandling.None (as somebody mentioned in comment); TypeNameHandling设置为TypeNameHandling.None (正如评论中提到的那样);
  • Replace not working types in string with working ones 将字符串中的工作类型替换为工作类型

Using TypeNameHandling.None may lead to wrong deserialization for exmaple when you have IEnumerable<BaseType> and that list contains subtype of BaseType . 当您拥有IEnumerable<BaseType>并且该列表包含BaseType子类型时,使用TypeNameHandling.None可能会导致exmaple的反序列化错误。

In that case you should go for second option. 在这种情况下,你应该选择第二种选择。 Basically you should replace any type that is not deserializing and replace it for example with List . 基本上,您应该替换任何未反序列化的类型,并将其替换为例如List

Sample code: 示例代码:

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 });
    }
}

Is there a Linq result in the serialized entity? 序列化实体中是否有Linq结果? Maybe defined as an IEnumerable and filled with a Linq Where result? 也许定义为IEnumerable并填充了Linq Where结果? It seems that's where your problem lies. 这似乎是你的问题所在。 You should convert it to a List or Array before serializing. 您应该在序列化之前将其转换为List或Array。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM