JSONconvert.Deserializer Indexing Issues

JsonConvert.Deserializer indexing issues

It seems like the stack is being serialized as a List. The problem is that this does not preserve the proper order when deconstructing the stack (the items are actually pushed in the reverse order). Here's a quick workaround to this issue:

using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace StackCollection
{
class Program
{
static void Main(string[] args)
{
Progress progress = new Progress();

progress.Items.Push(new Item { PlanID = null, PlanName = "Plan A" });

var jsonString = JsonConvert.SerializeObject(progress);
var temp = JsonConvert.DeserializeObject<Progress>(jsonString);

temp.Items.Push(new Item { PlanID = null, PlanName = "Plan B" });

jsonString = JsonConvert.SerializeObject(temp);
temp = JsonConvert.DeserializeObject<Progress>(jsonString);

temp.Items.Push(new Item { PlanID = null, PlanName = "Plan C" });

jsonString = JsonConvert.SerializeObject(temp);
temp = JsonConvert.DeserializeObject<Progress>(jsonString);

WriteLine(temp.Items.Peek().PlanName);

ReadLine();
}
}

class Progress
{
[JsonIgnore]
public Stack<Item> Items { get; set; }

public List<Item> ItemList { get; set; }

[OnSerializing]
internal void OnSerializing(StreamingContext context)
{
ItemList = Items?.ToList();
}

[OnDeserialized]
internal void OnDeserialized(StreamingContext context)
{
ItemList?.Reverse();
Items = new Stack<Item>(ItemList ?? Enumerable.Empty<Item>());
}

public Progress()
{
Items = new Stack<Item>();
}
}

class Item
{
public string PlanID { get; set; }

public string PlanName { get; set; }
}
}

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

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.

Json.NET can't Deserialize Indexed Property into Array

There is not an attribute in Json.Net that will directly convert your fluffy object into a list, but you can make a custom JsonConverter to do it without too much trouble, then decorate your Data class with an attribute to tell Json.Net to use the converter.

Here is what the converter might look like. Note that if there happen to be any gaps in the sequence of Fluff_n keys, this code will still maintain their relative order in the resulting list, but the gaps will not be preserved. I'm guessing this won't be an issue, but just FYI.

class FluffDataConverter : JsonConverter
{
readonly int PrefixLength = "Fluff_".Length;

public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Data));
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
List<Thing> things = jo.Properties()
.OrderBy(p => int.Parse(p.Name.Substring(PrefixLength)))
.Select(p => p.Value.ToObject<Thing>())
.ToList();
return new Data { Things = things };
}

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

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

To use this converter, just place a [JsonConverter] attribute on your Data class like this:

[JsonConverter(typeof(FluffDataConverter))]
public class Data
{
public List<Thing> Things { get; set; }
}

When you re-rerun your test code, it should work as you described.

Json.Net deserialize JSON objects with index as name

You don't need FeaturedArticles class, you can deserialize the JSON into a Dictionary<string, Articles> like this:

private void fetchFeaturedArticles()
{
var client = new RestClient (_featuredArticlesJsonUrl);
var request = new RestRequest (Method.GET);
var response = client.Execute (request);

Dictionary<string, Articles> _featuredArticles = JsonConvert.DeserializeObject<Dictionary<string, Articles>>(response.Content);

foreach (string key in _featuredArticles.Keys)
{
Console.WriteLine(_featuredArticles[key].Title);
}

}

Demo: https://dotnetfiddle.net/ZE1BMl

JSON.Net Deserialization error, My Class definition is wrong?

you have to use list of objects, not an object

Dim oResult = JsonConvert.DeserializeObject(Of List(Of MCMusicElements))(sRB)

dtDataTable.Rows(index).Item(1) = oResult(0).MIK_Energy

Error when deserializing JSON to Object

The real issue here is that you are trying to deserialize into a List<object> but your JSON actually represents a single object containing a data property which then contains a list of objects. That is why you are getting this error. Json.Net can't deserialize a single object into a list. I think what you really want to do is define a container class like this:

class Root
{
public List<Dictionary<string, object>> Data { get; set;}
}

Then deserialize like this:

var data = JsonConvert.DeserializeObject<Root>(jsonData).Data;

You will then end up with a list of dictionaries, where each dictionary represents one item in the JSON array. The dictionary key-value pairs are the dynamic values in each item. You can then work with these as you would with any other dictionary. For example, here is how you would dump out all the data:

foreach (var dict in data)
{
foreach (var kvp in dict)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}
Console.WriteLine();
}

Fiddle: https://dotnetfiddle.net/6UaKhJ

Error Deserializing JSON Object/Array using newtonsoft

Look at Camilo Martinez answer on this discussion :
Deserializing JSON when sometimes array and sometimes object

Basically, you'll need to add the JsonConverter attribute to your BookingInfo property and handle the conversion in a JsonConverter implementation.

public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}

public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}

public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonConverter(typeof(SingleValueArrayConverter<BookingInfo>))]
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}

public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}

public class Connection
{
public string SegmentIndex { get; set; }
}

And here's the converter :

public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}

public override bool CanConvert(Type objectType)
{
return true;
}
}

Newtonsoft JSON.NET Deserialization error

You must browse through Response<> and MyEntity and see how collections are initialized. This tells us that one of the collections in some class is created using Where method from linq. 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. Then you have 2 solutions:

  • Set TypeNameHandling to TypeNameHandling.None (as somebody mentioned in comment);
  • 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.

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.

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

Newtonsoft.Json Deserialize fails

The problem was that my class had a non default constructor and no default constructor. The error message is irrelevant.



Related Topics



Leave a reply



Submit