JsonConvert.DeserializeObject, Index was outside the bounds of the array

六眼飞鱼酱① 提交于 2020-01-14 14:55:07

问题


All of this is origianlly from https://github.com/JamesNK/Newtonsoft.Json/issues/469

Posted here because I first looked on SO and didn't see anything, so I posted on the project's GitHub page.


We're currently using JsonConvert.SerializeObject and JsonConvert.DeserializeObject<T> to send data between a client and server.

I created a tool that creates 10 clients, sends a command to 10 different servers, the servers serialize a response and send it back over the network, then the 10 clients deserialize the object on the local machine.

I'm running these 10 tasks concurrently in the thread pool, and about 20% of the time all of the JsonConvert.DeserializeObject calls fail with the following stack trace:

Error: Index was outside the bounds of the array.
at System.Collections.Generic.List1.Add(T item)
at System.Collections.Generic.List1.System.Collections.IList.Add(Object item)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at MyClientCode()

MyClientCode() is using DeserializeObject like this:

string json = GetServerResponse();
return JsonConvert.DeserializeObject<ResponseObject>(json);

The ResponseObject is pretty big, and includes several composite objects. However, I can save the json and deserialize it properly with DeserializeObject, so I don't think the object structure is the problem.

Doing some research of the List error indicates that this occurs when trying to modify a List object concurrently.


回答1:


From James Newton-King:

A new JsonSerializerInternalReader is created each time you deserialize an object. Each deserialization happens in its own state. A high volume server that it deserializing incoming JSON will be deserializing many many things at the same time without issue.

My guess is you have multiple deserializers working over the same list.


Thanks James. After digging deeper I found that you're right, we were using the same list object for multiple instances of the deserialized type. Specifically, the object looked something like this:

class Obj {
    static List<string> _validSelections = new List<string>() { "One", "Two", "Three", "Four" };
    public IEnumerable<string> ValidSelections { get { return _validSelections; } }
    ... more ...
}

The exception was being thrown on line 1261 of JsonSerializerInternalReader.cs when trying to add objects to the list concurrently.

After seeing how this is implemented in our code, I am going to get rid of the static backing since it wasn't providing us anything anyway.



来源:https://stackoverflow.com/questions/28095244/jsonconvert-deserializeobject-index-was-outside-the-bounds-of-the-array

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!