I would like to serialize a Dictionary to a JSON array with ASP.NET Web API. To illustrate the current output I have the following setup:
Dictionary<int, TestClass> dict = new Dictionary<int, TestClass>();
dict.Add(3, new TestClass(3, "test3"));
dict.Add(4, new TestClass(4, "test4"));
The TestClass is defined as follows:
public class TestClass
{
public int Id { get; set; }
public string Name { get; set; }
public TestClass(int id, string name)
{
this.Id = id;
this.Name = name;
}
}
When serialized to JSON I get the following output:
{"3":{"id":3,"name":"test3"},"4":{"id":3,"name":"test4"}}
Unfortunately this is an Object and not an Array. Is it somehow possible to achieve what I'm trying to do? It doesn't need to be a Dictionary but I need the Id's of the TestClass to be the Key's of the Array.
With the following List it is correctly serialized to an array but not with the correct Key's.
List<TestClass> list= new List<TestClass>();
list.Add(new TestClass(3, "test3"));
list.Add(new TestClass(4, "test4"));
Serialized to JSON:
[{"id":3,"name":"test3"},{"id":4,"name":"test4"}]
but I need the Id's of the TestClass to be the Key's of the Array.
In javascript what you call an array must be an object in which the indexes are 0-based integers. This is not your case. You have id 3 and 4 which cannot be used as indexes in a javascript array. So using a List is the correct approach here.
Because if you want to use arbitrary indexes (as in your case you have some integers that are not 0-based) this is no longer an array but an object in which those integers or strings are simply the properties of this object. That's what you achieve with the Dictionary.
You could convert the object to an array client-side using vanilla js.
var jsonFromServer = {"3":{"id":3,"name":"test3"},"4":{"id":4,"name":"test4"}};
var expected = [];
Object.keys(jsonFromServer).forEach(key => expected[+key] = json[key]);
console.log(expected.length); // 5
console.log(expected[0]); // undefined
console.log(expected[1]); // undefined
console.log(expected[2]); // undefined
console.log(expected[3]); // Object { id: 3, name: "test3" }
console.log(expected[4]); // Object { id: 4, name: "test4" }
Related
I'm quite new to JSON with C# (Using VS2017). Tried accessing each element of this object via code (e.g. Getting the strings "Obj1", "Obj2", "Obj3" and then the values of each of their members (Id and name).
I do not know in advance how many "ObjX" there will be or their names. I'm trying to load this list into some class and then convert it into a CSV (or SQL inserts).
Tried with JSON.net and JsonFx but I think my skills are just not strong enough to understand how to do this other than brute-force string manipulation functions. Can anyone help?
{
"OBJ1":{
"id":1,
"name":"Name1",
},
"OBJ2":{
"id":2,
"name":"Name2",
},
"OBJ3":{
"id":3,
"name":"Name3",
}
}
Create a class, MyClass with two properties, int Id and string Name.
public class MyClass
{
public int Id {get; set;}
public string Name {get;set;}
}
Then, depending on how you want to do it you can either deserilize it to a Dictionary or create a MyClassRoot object with three MyClass properties.
I recommend the Dictionary approach.
If you use the Dictionary approach your code will still work if more properties gets added to the JSON. If you use the MyClassRoot solution you will need to add the corresponding property to the MyClassRoot if the json updates.
Then with JSON.Net you can deserialize the object like this.
var result = JsonConvert.DeserializeObject<Dictionary<string, MyClass>>(json);
The "OBJ1", "OBJ2" and so on will then be keys in the dictionary and you can access the values like this:
var obj1 = result["OBJ1"];
var obj1Name = obj1.Name;
var obj1Id = obj1.Id;
To get all the MyClass objects to a list, simply do the following:
var list = result.ToList();
MyClassRoot approach(not recommended at all, just a POC):
public class MyClassRoot
{
public MyClass Obj1 {get;set;}
public MyClass Obj2{get;set;}
public MyClass Obj3{get;set;}
}
var result = JsonConvert.DeserializeObject<MyClassRoot>(json);
var obj1Name = result.Obj1.Name;
var obj1Id = result.Obj1.Id;
I am trying to get value of label from following string.
I have a string in this format.
var string = "[{\"key\":\"182\",\"label\":\"testinstitution\"}]"
dynamic dict = new JavaScriptSerializer().Deserialize<dynamic>(string);
string inst = dict["label"]; //This is not working
I am getting dict in form of key value pair object but I am not able to get value of label. I cannot use JSON.NET.
To retrieve value of label from your string use string inst = dict[0]["label"];.
Explanation
The reason why you need additional [0] is because deserialization returns array of key value pairs. First object from that array will go to index [0], second object from array to index [1] an so on. Your string has array of only one object. Here is an example of when you have two objects, where second object has another object inside of it, in which case you would have to write dict[1]["foo"]["two"] to get to desired value:
var myString = #"
[
{
'one': '1'
},
{
'foo':
{
'two': '2'
}
}
]";
dynamic dict = new JavaScriptSerializer().Deserialize<dynamic>(myString);
string inst = dict[1]["foo"]["two"];
Additional FYI
If you know structure of your data consider using strong types (as suggested in one of the comments). Here is example of how you would do it:
public class Data
{
public string key { get; set; }
public string label { get; set; }
}
class Program
{
static void Main(string[] args)
{
var myString = #"
[{
'key': 182,
'label': 'testinstitution'
}]";
List<Data> dict = new JavaScriptSerializer().Deserialize<List<Data>>(myString);
foreach (var d in dict)
Console.WriteLine(d.key + " " + d.label);
Console.ReadKey();
}
}
Note that properties key and value in your Data object much match names of those in your array of objects exactly.
I have an incoming JSON, which consists array of some objects, say, Foo. I deserialize them with
result = JsonConvert.DeserializeObject<List<Foo>>(message);
Now i want to add a string property to Foo, which will store it's JSON (which i received), so that Foo'll look like:
public class Foo
{
public int MyInt { get; set; }
public bool MyBool { get; set; }
public string JSON { get; set; }
}
But i don't know how can i say JSON.Net the way it can populate such a field..
UPD
I'll clearify what i want. Say i receive JSON:
[{"MyInt":1,"MyBool":0},{"MyInt":2,"MyBool":0},{"MyInt":3,"MyBool":1}]
Here is array of 3 objects and i want, when deserializing, to add corresponding part of json to object, so that:
First object will contain {"MyInt":1,"MyBool":0}
Second object will contain {"MyInt":2,"MyBool":0}
Third object will contain {"MyInt":3,"MyBool":1}
in their JSON Property
I'll be gratefull for any help!
This is one way to do it, but it doesn't maintain the exact original JSON - but it does provide a static record of the original JSON (but without the exact format of the original values - i.e. Bool maybe be 0/1 or true/false):
var message = #"[{""MyInt"":1,""MyBool"":0},{""MyInt"":2,""MyBool"":0},{""MyInt"":3,""MyBool"":1}]";
var foos = JsonConvert.DeserializeObject<List<Foo>>(message);
var t = JsonConvert.SerializeObject(foos[0]);
foos = foos.Select(s => new Foo() { MyBool = s.MyBool, MyInt = s.MyInt, JSON = JsonConvert.SerializeObject(s) }).ToList();
If you are dealing with a lot of Foos, then you might want to find a more efficient way. There might be a way to 'update' using linq, rather than creating a new list.
Okay, i found an answer. I didn't know that i can deserialize message into JArray and then enumerate it (good job, newtonsoft:) ). Here is what i endede up with:
if (tokenType is JArray)
{
var arr = JsonConvert.DeserializeObject(message) as JArray;
foreach (var item in arr)
{
try
{
var agentParameter = item.ToObject<Foo>();
agentParameter.JSON = item.ToString();
result.Add(agentParameter);
}
catch (Exception)
{
LogProvider.Error(string.Format("Failed to Deserialize message. Message text: \r\n {0}", item.ToString()));
}
}
}
I am trying to convert a nested JSON object on an ASP.NET server. The incoming JSON string looks something like this -
data: {
user_id: 1,
taskid: "1234",
list: {
"item-1": { one: 1, two: 2 },
"item-2": { one: 1, two: 2 }
//.. where number of items is unknown
}
}
I have tried to decode the data using JSON.Decode this way
public class Data {
public int user_id { get; set; }
public string taskid { get; set; }
public List<object> list { get; set; }
}
public class DataList {
List<Data> data { get; set; }
}
// if isPost etc..
var decodedData = JSON.Decode<DataList>(Request["data"])
But when I try and iterate over decodedData I am getting an error -
foreach statement cannot operate on variables of type
'ASP._Page_that_cshtml.DataList' because
'ASP._Page_that_cshtml.DataList' does not contain a public definition
for 'GetEnumerator'
When I try casting the decodedData to a List this way -
List<Data> decodedData = JSON.Decode<DataList>(Request["data"])
I throw another error
CS0030: Cannot convert type 'ASP._Page_that_cshtml.DataList' to 'System.Collections.Generic.List<ASP._Page_that_cshtml.DataList>'
Could you please suggest an appropriate method to convert nested JSON objects into a C# object and iterating over it?
PS: trailing semi-colons omitted on-purpose
List<Data> decodedData = JSON.Decode<DataList>(Request["data"])
Should Be
var decodedData = JSON.Decode<List<Data>>(Request["data"])
var myDataList = new DataList() { data = decodedData; }
Your example is not valid json. You should have a collection [] for list:
data: {
"user_id": 1,
"taskid": "1234",
"list": [
{
"one": 1,
"two": 2
},
{
"one": 1,
"two": 2
}
]
}
The first error you are getting is quite right, your class DataList does not contain a definition for GetEnumerator which is required for a foreach statement. You will need to iterate over the property, so iterate over decodedData.data.
The second error is again correct, as you are trying to cast DataList to a type of List, something C# has no idea how to do. You would again need to create your DataList, then set the property data to the type List.
Try iterating over decodedData.data instead.
decodedData is a DataList, and the DataList class has a member data which is a List<Data>. List<Data> has a GetEnumerator method, as required by foreach.
Alternatively, you could add a GetEnumerator method to DataList:
public IEnumerator GetEnumerator() { return data.GetEnumerator(); }
You can try decoding the JSON into an array of Data objects, and then calling the ToList() extension method on that array.
var dataArray = JSON.Decode<Data[]>(Request["data"]);
var list = dataArray.ToList();
I have just started using Newtonsoft.Json (Json.net). In my first simple test, I ran into a problem when deserializing generic lists. In my code sample below I serialize an object, containing three types of simple integer lists (property, member var and array).
The resulting json looks fine (the lists are converted into json-arrays). However, when I deserialize the json back to a new object of the same type, all list items are duplicated, expect for the array. I've illustrated that by serializing it a second time.
From searching around, I've read that there may be a "private" backing field to the lists that the deserializer also fills.
So my question is: Is there a (preferably simple) way to avoid duplicate items in following case?
Code
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSerializeExample
{
public class Program
{
static void Main()
{
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json);
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
}
}
public class SomeData
{
public string SimpleField;
public int[] IntArray;
public IList<int> IntListProperty { get; set; }
public IList<int> IntListMember;
public SomeData()
{
SimpleField = "Some data";
IntArray = new[] { 7, 8, 9 };
IntListProperty = new List<int> { 1, 2, 3 };
IntListMember = new List<int> { 4, 5, 6 };
}
}
}
Resulting output
First : {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6],"IntListProperty":[1,2,3]}
Second: {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6,4,5,6],"IntListProperty":[1,2,3,1,2,3]}
There may be some overlap here with Json.Net duplicates private list items. However, I think my problem is even simpler, and I still haven't figured it out.
That is because you are adding items in the constructor. A common approach in deserializers when processing a list is basically:
read the list via the getter
if the list is null: create a new list and assign via the property setter, if one
deserialize each item in turn, and append (Add) to the list
this is because most list members don't have setters, i.e.
public List<Foo> Items {get {...}} // <=== no set
Contrast to arrays, which must have a setter to be useful; hence the approach is usually:
deserialize each item in turn, and append (Add) to a temporary list
convert the list to an array (ToArray), and assign via the setter
Some serializers give you options to control this behavior (others don't); and some serializers give you the ability to bypass the constructor completely (others don't).
I'm pretty sure that this post is not relevant anymore, but for future reference, here a working solution.
Just need to specify that ObjectCreationHandling is set to Replace, i.e. Always create new objects and not to Auto (which is the default) i.e. Reuse existing objects, create new objects when needed.
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace });
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
I encountered a similar issue with a different root cause. I was serializing and deserializing a class that looked like this:
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
public class AppointmentRevision
{
public List<Attendee> Attendees { get; set; }
}
When I serialized this, CurrentRevision was being serialized too. I'm not sure how, but when it was deserializing it was correctly keeping a single instance of the AppointmentRevision but creating duplicates in the Attendees list. The solution was to use the JsonIgnore attribute on the CurrentRevision property.
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
[JsonIgnore]
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
How to apply ObjectCreationHandling.Replace to selected properties when deserializing JSON?
Turns out (I'm in 2019), you can set the list items in your constructor as you were doing in your question. I added the ObjectCreationHandling.Replace attribute above my declaration of the list, then serialising should replace anything stored in the list with the JSON.