John Carther
John Carther

Reputation: 43

Display JSON object array in datagridview

Im trying to parse JSON which is I believe object array. I can parse simple single JSON with JObject.Parse but this one gives me headache.

{
"2": {
  "num": 5,
  "average": 10,
  "state": true,
  "id": 2,
  "buy": 10,
  "name": "name"
 },
"6": {
  "num": 5,
  "average": 10,
  "state": true,
  "id": 6,
  "buy": 20,
  "name": "name"
 }
}

I had idea but dont know how to deal with numbers before bracket. Its always the same as "id".

I tried to use Newtonsoft.Json something like this:

 List<Items> objlis = (List<Items>)Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(List<Items[]>));

However it says that "the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly."

Upvotes: 3

Views: 2209

Answers (3)

dbc
dbc

Reputation: 116990

It looks as though the sending system chose to serialize a sparse list as a JSON object where the object names are the list indices, rather than as a JSON array. But Json.NET maps JSON arrays from and to c# lists so your deserialization to List<Items> fails with the exception message the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

The simplest way to deserialize such a JSON object is as a dictionary such as Dictionary<string, Items> or SortedDictionary<int, Items> as is shown in this question, e.g.:

var dict = JsonConvert.DeserializeObject<SortedDictionary<int, Items>>(json);

If you specifically require the JSON to be deserialized as a list, you can write a custom JsonConverter to do the mapping:

public class ListToDictionaryConverter<T> : JsonConverter where T : class
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(List<T>).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var list = existingValue as List<T> ?? (List<T>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
        if (reader.TokenType == JsonToken.StartArray)
            serializer.Populate(reader, list);
        else if (reader.TokenType == JsonToken.StartObject)
        {
            var dict = serializer.Deserialize<Dictionary<int, T>>(reader);
            foreach (var pair in dict)
                list.SetOrAddAt(pair.Key, pair.Value, default(T));
        }
        else
        {
            throw new JsonSerializationException(string.Format("Invalid token {0}", reader.TokenType));
        }
        return list;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var list = (IList<T>)value;
        writer.WriteStartObject();
        for (int i = 0; i < list.Count; i++)
        {
            // Omit null values.
            if (list[i] == default(T))
                continue;
            writer.WritePropertyName(((JValue)i).ToString());
            serializer.Serialize(writer, list[i]);
        }
        writer.WriteEndObject();
    }
}

public static class ListExtensions
{
    public static void SetOrAddAt<T>(this IList<T> list, int index, T value, T defaultValue = default(T))
    {
        if (list == null)
            throw new ArgumentNullException("list");
        list.EnsureCount(index + 1, defaultValue);
        list[index] = value;
    }

    public static void EnsureCount<T>(this IList<T> list, int count, T defaultValue = default(T))
    {
        if (list == null)
            throw new ArgumentNullException("list");
        int oldCount = list.Count;
        if (count > oldCount)
        {
            for (int i = oldCount; i < count; i++)
                list.Add(defaultValue);
        }
    }
}

Then use it like:

var objlis = JsonConvert.DeserializeObject<List<Items>>(json, new ListToDictionaryConverter<Items>());

Sample fiddle.

Upvotes: 0

Jyoti Kumari
Jyoti Kumari

Reputation: 62

You can built table like following from Json and then call to datagridview

List<User> allusers = JsonConvert.DeserializeObject<List<User>>(jsonString);

public static DataTable MakeDataTable<T>(this IList<T> data)
        {
        PropertyDescriptorCollection props =
        TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        for(int i = 0 ; i < props.Count ; i++)
        {
        PropertyDescriptor prop = props[i];
        table.Columns.Add(prop.Name, prop.PropertyType);
        }
        object[] values = new object[props.Count];
        foreach (T item in data)
        {
        for (int i = 0; i < values.Length; i++)
        {
            values[i] = props[i].GetValue(item);
        }
        table.Rows.Add(values);
        }
        return table;        
    }

Upvotes: 1

Jyoti Kumari
Jyoti Kumari

Reputation: 62

var result = JsonConvert.DeserializeObject<List<JsonResult>>(input);
dataGridView.DataSource = result;

Upvotes: 0

Related Questions