Deserialize JSON array of arrays into c# class [duplicate] - c#

This question already has answers here:
How to deserialize a JSON array into an object using Json.Net?
(2 answers)
Closed 2 years ago.
I have a class in the format:
public class Person
{
public string Name {get;set;}
public int Age {get;set;}
public string Car {get;set;}
}
What i tried to read the JSON from a file:
using (StreamReader r = new StreamReader(path))
{
string json = r.ReadToEnd();
//var items = JsonConvert.DeserializeObject<IEnumerable<Person>>(json);
}
When I got the JSON in a string I got that in the format below:
[
["John", 30, "BMW"],
["Tim", 45, "Ford"],
["Kim", 34, "Toyota"]
]
I thought that JSON would be Deserialize in that IEnumerable<Person>, but it couldn't.
What is the correct way to deserialize the JSON string with that Person class?

Since you have only values without properties names in your JSON, you can deserialize it into sequence of collection objects, like IEnumerable<string[]>, IEnumerable<List<string>> or List<List<string>>. Then parse every item to Person manually (assuming that you have the same structure for all items, otherwise you'll need an additional logic for checking an errors)
var result = JsonConvert.DeserializeObject<IEnumerable<string[]>>(jsonString);
var persons = result
.Select(item => new Person { Name = item[0], Age = int.Parse(item[1]), Car = item[2] })
.ToList();

If you want to deserialize into a Person object, then your array items need to be in a key/value object structure instead of an array of strings. Your JSON should be the following:
[
{
name: "John",
age: 30,
car: "BMW"
},
{
name: "Tim",
age: 45,
car: "Ford"
},
{
name: "Kim",
age: 34,
car: "Toyota"
}
]
EDIT:
Since you are unable to change the input file structure, I would recommend reading in as an IEnumerable<string[]>.
Then you can proceed to read with the following:
var rawPersons = JsonConvert.Deserialize<IEnumerable<string[]>>(json);
If you create a constructor on your Person class, then it can populate your properties from the raw Person object:
public Person(string[] parts) {
if(parts.Length != 3) {
throw new ArgumentException("Not a valid person.");
}
Name = parts[0];
var validAge = int.TryParse(parts[1], out Age);
if(!validAge) {
throw new ArgumentException("Age is not an integer.");
}
Car = parts[2];
}
Lastly, you can use a projection on your raw persons to get a collection of Person objects.
var persons = rawPersons.Select(p => new Person(p));

Related

Can I use c# methods when serializing to JSON

I am using JSON.Net to convert the data from my c# program to JSON format using JSON.NET. I was wondering if there was any way in which I could use methods that I use in my c# program when serialising to json?
Bit of background context:
There exists a class Students which has attributesString StudentName, Guid StudentId and Dictionary<String, Int> Grades Record where subject names are the keys and grades are the values.
There exists another class ClassOfStudents which has an attribute List<Student> Students.
I am trying to print out the list of all the students names. I have managed to do this on c# with the method below:
public static void ViewStudentsPool()
{
Console.Write(Line);
Console.WriteLine("\nPlease find updated students pool below");
Console.Write(Line + "\n");
foreach (var studentname in ClassOfStudents.Students)
{
Console.WriteLine("Student Id: " + studentname.StudentId + "| Student Name: " + studentname.StudentName);
}
Console.Write(Line + "\n\n");
}
I was wondering if I could then use this method when serialising to JSON.
I currently have the below, which prints out all attributes of the students which I do not want, I only want to print their names out.
JsonSerializer serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;
using (StreamWriter sw = new StreamWriter(#"c:\Students.txt"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
serializer.Serialize(writer, ClassOfStudents.Students );
}
I have tried replacing ClassOfStudents.Studentson the last line with ViewStudentsPool() but it shows an error.
Any help on how I can print out only the student names?
Thanks
A simple approach would be to just map your ClassOfStudents.Students list to the structure that you're looking for, using LINQ, for example:
var studentsWithNamesOnly = ClassOfStudents.Students
.Select(x => new { x.StudentName });
You can take this output and serialise that instead of your original ClassOfStudents.Students variable, like this:
serializer.Serialize(writer, studentsWithNamesOnly);
This would produce something like this:
[
{ "StudentName": "Name1" },
{ "StudentName": "Name2" },
...
]
You don't have to create a new anonymous object in the Select like I've done here: You could format a string like your original example, if that's what's needed.

Converting C# List into JSON specific format

I have a graph in my view which looks like this:
var hourlyGraph = Morris.Bar({
element: 'graph_bar',
data: [
#foreach (var item in ViewBag.HourlyGraph)
{
#:{device: '#item.Hour.ToString("D2"):00', geekbench:#item.Sales },
}
],
xkey: 'device',
ykeys: ['geekbench'],
labels: ['Sold'],
barRatio: 0.4,
barColors: ['#0A4D70', '#34495E', '#ACADAC', '#3498DB'],
xLabelAngle: 35,
hideHover: 'auto',
resize: true
});
This is a morris chart. Note how the data is set up here:
[
#foreach (var item in ViewBag.HourlyGraph)
{
#:{device: '#item.Hour.ToString("D2"):00', geekbench:#item.Sales },
}
]
And now I need to fill the chart with new data. In my Action I have created a list which contains 2 properties:
public int Hour {get;set;}
public int Sales {get;set;}
And they are stored into a list typed of:
var HourlyGraph = new List<HourlyGraph>();
Now I'd like to convert this list into a JSON format which would look something like this:
[
{device: '0', geekbench:5 },
{device: '1', geekbench:13 },
{device: '2', geekbench:25 },
{device: '3', geekbench:14 },
{device: '4', geekbench:16 },
]
Where value for device would be = hour, and geekbench = sales ...
How could I do this in C#?
With Json.Net and Linq it's easy:
string myJson =
JsonConvert.SerializeObject(mylist.Select(item=>
new {device=item.Hour, geekbench=item.Sales}));
You project an anonymous type with the fields and names that you'd like, and let Newtonsoft.Json do the rest.
since you are using mvc why not use return Json() it will convert the object to json string you can use it like
public ActionResult Myaction()
{
var HourlyGraph = new List<HourlyGraph>();
return Json(HourlyGraph.Select(x => new {Hour=x.Hour,Sales=x.Sales }));
}
You can achieve the desired output by using LINQ Anonymous Type
As per example following is class
public class HourlyGraph
{
public int Hour { get; set; }
public int Sales { get; set; }
}
Import Namespace System.Web.Script.Serialization which is a Microsoft's Inbuilt Class for dealing with JSON. You will need to refer additional assembly named System.Web.Extensions using 'Add References'.
using System.Web.Script.Serialization;
Declare List and Convert into customized JSON Format
var listHourlyGraph = new List<HourlyGraph>();
//Adding some Sample Values
listHourlyGraph.Add(new HourlyGraph() { Hour = 0, Sales = 5 });
listHourlyGraph.Add(new HourlyGraph() { Hour = 1, Sales = 10 });
//Declaring JavaScriptSerialzer Object
var serialzer = new JavaScriptSerializer();
//Using Serialize Method which returns back a JSON String
//We are using LINQ SELECT Method to create a new anonymous return type which contains our custom return types
string s = serialzer.Serialize(listHourlyGraph.Select(x => new { device = x.Hour, geekbench = x.Sales } ));
You will get the following output in 's' variable
[{"device":0,"geekbench":5},{"device":1,"geekbench":10}]
Note: If you want to get performance optimizations then you are better using Newtonsoft JSON Library instead of Microsoft's Default JSON Library.

De/Serialize C# data object with nested derived objects to/from JSON

Is there C# library that can serialize tree-like structure of .NET/C# strongly typed objects in a single call?
EDIT: I want to be able to deserialize JSON into variable of type object (or some other root class, but object would be preferable) and then find out what I just deserialized by calling GetType() on this variable. So type of each instance of each class (except bool/int/float/string) and each List<> should be stored as part of serialized JSON and retrieved automatically.
For example if I have these C# classes:
public class House
{
public int Number;
public List<Room> Rooms;
}
public class Room
{
public string Name;
public int Floor;
}
public class Bathroom : Room
{
public bool IsWet;
}
And initialize my in-memory data structure like this (note that I use generic List class, not C# array):
House myHouse = new House();
myHouse.Number = 13;
myHouse.Rooms = new List<Room>();
myHouse.Rooms.Add(new Room());
myHouse.Rooms[0].Name = "some room";
myHouse.Rooms[0].Floor = 0;
myHouse.Rooms.Add(new Bathroom());
myHouse.Rooms[0].Name = "other room";
myHouse.Rooms[0].Floor = 3;
myHouse.Rooms[0].IsWet = true;
After that I want to be able to call something like this:
string jsonHouse = JSON.Serialize(myHouse);
To get (for example) this in my jsonHouse variable (EDIT: note that it stores type of each class as part of JSON. Also note the instance of derived class BathRoom stored in List):
{
"class": "House",
"Number": "13",
"Rooms": [
{
"class": "Room",
"Name": "some room"
"Floor": "0",
},
{
"class": "Bathroom",
"Name": "other room"
"Floor": "0",
"IsWet": "true",
},
],
}
and finally call something like this:
House copyOfMyHouse = JSON.Deserialize(jsonHouse);
EDIT: this (right above) call seems to be misleading. instead of above call I should expect deserialization to be like this:
object copyOfMyHouse = JSON.Desrialize(jsonHouse);
To get instance of class House in my copyOfMyHouse variable (of type object) without specifying to JSON.Deserialize what type do I expect from it - I may not know it in advance.
to get exact copy of what I had in myHouse variable, with an instance of List generic class containing references to exact copies of two instances of Room class.
Is there any JSON serializer written in C# that can do this?
Preferably FOSS/FLOSS one that can be (legally) used in commercial projects.
Format of JSON string may be different from what I used above as example (e.g. your proposed solution may store List as JSON objects instead of arrays, other text formats like BSON or XML are acceptable)
Single-call use for any number of nesting levels is mandatory - otherwise any JSON serializer would fit.
Also ability to serialize Dictionary to JSON object is desirable.
Please ask clarifying questions if my description of what I look for is unclear.
Basically, you want to serialize/deserialize an object containing derived types. The solution is using Json.NET. It's very simple and easy to use. Here is an example with your data:
House myHouse = new House();
myHouse.Number = 13;
myHouse.Rooms = new List<Room>();
Room room1 = new Room();
room1.Name = "some room";
room1.Floor = 0;
myHouse.Rooms.Add(room1);
Room room2 = new Room();
room2.Name = "other room";
room2.Floor = 3;
myHouse.Rooms.Add(room2);
Bathroom bathroom = new Bathroom();
bathroom.Name = "Bathroom";
bathroom.Floor = 2;
bathroom.IsWet = true;
myHouse.Rooms.Add(bathroom);
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;
string json = JsonConvert.SerializeObject(myHouse, settings);
Console.WriteLine("Serialize finished!");
House house = JsonConvert.DeserializeObject<House>(json, settings);
Console.WriteLine($"House number: {house.Number}; Total rooms: {house.Rooms.Count}");
foreach (Room room in house.Rooms)
{
if (room is Bathroom)
{
var temp = room as Bathroom;
Console.WriteLine($"Room name: {temp.Name}, wet: {temp.IsWet}");
}
else
{
Console.WriteLine($"Room name: {room.Name}");
}
}
Console.WriteLine("Deserialize finished!");
Console.ReadLine();
Here is the JSON string you got after the serialization:
{
"Number": 13,
"Rooms": [
{
"Name": "some room",
"Floor": 0
},
{
"Name": "other room",
"Floor": 3
},
{
"$type": "DemoApp.Bathroom, DemoApp",
"IsWet": true,
"Name": "Bathroom",
"Floor": 2
}
]
}
And you got back the object after deserialize the string.
Newtonsoft.JSON (sometimes known as JSON.NET) is good and available as a NuGet package. Then you can write something like:
var value = new { ID = 1, Name="test"};
string serialized = JsonConvert.SerializeObject(value);
And to deserialize (the simplest option, but there are lots of good ways to do it):
result = JsonConvert.DeserializeObject(jsonResponse);
While other answers already provide good solutions, here's one using the DataContractJsonSerializer class.
var jsonString = "";
var jsonSerializer = new DataContractJsonSerializer(typeof(House));
using (var memoryStream = new MemoryStream())
using (var streamReader = new StreamReader(memoryStream))
{
jsonSerializer.WriteObject(memoryStream, myHouse);
memoryStream.Position = 0;
jsonString = streamReader.ReadToEnd();
}
Console.Write("JSON form of Person object: ");
Console.WriteLine(jsonString);

Json deserializer

im currently making my first steep with json and well im complety confused.
I found many examples how to deserialize json files but nothing helps me.
{
"102": {
"id": 102,
"name": "cvmember3",
"profileIconId": 28,
"revisionDate": 1373593599000,
"summonerLevel": 1
},
"101": {
"id": 101,
"name": "IS1ec76a704e9b52",
"profileIconId": -1,
"revisionDate": 1355466175000,
"summonerLevel": 1
}
}
This is the json i object i got, the problem is im to stupid to deseralize it.
What i tried till now:
String name= (string) new JavaScriptSerializer().Deserialize<Dictionary<String, object>>(json)["name"];
Im missing the index, and dont know how to add it
anyone, can say me the correct line to deserialize, i has acces to the libary json.net
Alternatively you could define a class for the data you're going to get back and then parse your JSON into a dictionary something like this:
public class DataClass
{
public int id;
public string name;
public int profileIconId;
public long revisionDate;
public int summonerLevel;
}
Then
Dictionary<int, DataClass> myDictionary = JsonConvert.DeserializeObject<Dictionary<int, DataClass>>(json);
string foundName = myDictionary[102].name;
If you only want one item from the string (i only need to get one arttribut), you can use NewtonSoft to fish out the item you need:
using Newtonsoft.Json.Linq;
// read from where ever
string jstr = File.ReadAllText("C:\\Temp\\101.json");
JObject js = JObject.Parse(jstr);
var data102 = js["102"]["name"]; // == "cvmember3"
var data101 = js["101"]["name"]; // == "IS1ec76a704e9b52"
Console.WriteLine("Name for 101 is '{0}'", data101.ToString());
Console.WriteLine("Name for 102 is '{0}'", data102.ToString());
Output:
Name for 101 is 'IS1ec76a704e9b52'
Name for 102 is 'cvmember3'
This is a quick way to get at just one item value but it assumes you know what it looks like and where it is stored.

In C# how can I deserialize this json when one field might be a string or an array of strings?

I have an asp.net-mvc website and i am reading in Json string from a Database. Here is the following json in a DB. It could look like this:
{"description": "Test", "contacts": ["joe#gmail.com", "bill#yahoo.com"], "enabled": true}
or this:
{"description": "Test", "contacts": "joe#gmail.com, bill#yahoo.com", "enabled": true}
so as you can see, the contacts field is either:
a string (with items separated by commas)
an array of strings.
I want to convert to this class:
public class MyJob
{
public string description;
public string[] contacts;
public string enabled;
}
when i try to assign just to a string (changing the above to this: public string contacts;
) using the JavascriptSerializer():
var serializer = new JavaScriptSerializer();
string contacts = serializer.Deserialize<MyJob>(theAboveJsonString).contacts;
I get this error in the cases where its an array: Type 'System.String' is not supported for deserialization of an array.
what is the best way to go about deserializing this to handle the case of:
a string
an array of strings.
for the contact field. I am happy to put any conditional logic needed . .
I tried this:
var contacts = serializer.Deserialize<MyJob>(theAboveJsonString).contacts;
if (contacts is string)
{
jobInfo.contacts = contacts;
}
else
{
jobInfo.contacts = String.Join("; ", contacts );
}
but that didn't seem to fix as i am still getting the error above when its an array
try
var contacts = (new JavaScriptSerializer().DeserializeObject(theAboveJsonString) as Dictionary<string, object>)["contacts"];
if (contacts is object[])
{
jobInfo.contacts = String.Join("; ", contacts as object[]);
}
else
{
jobInfo.contacts = contacts.ToString();
}
For reference see MSDN and here.
You may be interested in some details here: JSON.net - field is either string or List<string>
If you're willing to use Json.NET, have this function:
public string[] getAsArray(JToken token)
{
if (token.HasValues)
{
return token.Select(m => string(m)).ToArray();
}
else
{
return ((string)token).Split(",").Select(s => s.Trim()).ToArray();
}
}
Then usage:
var json = "...";
JObject o = JObject.Parse(json);
string[] contacts = getAsArray(o["contacts"]);
For either JSON the result should be the same.
Try to deserialize contacts into a string array instead of a plain string:
string[] contacts = serializer.Deserialize<MyJob>(theAboveJsonString).contacts;
if the JSON variable is holding a plain string, use:
string[] contacts = serializer.Deserialize<MyJob>(theAboveJsonString).contacts.Split(',');

Categories