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

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

Related

C# Unable to modify Json with Newtonsoft

I have a string type variable named final and it contains the following Json:
{
"Game": {
"Player_Decks": {
"1": {
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
"2": {
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
},
"Deck_NoCards": {}
}
}
My code looks like this: (taken from here: https://www.newtonsoft.com/json/help/html/ModifyJson.htm)
JObject rss = JObject.Parse(final);
JObject channel = (JObject)rss["Game.Player_Decks.1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
I want to add another value after Card_Count, but I have a feeling that my string isn't "compatible" or something. What can be done here to fix my problem?
Reposting comment as answer here:
You cannot access the nested object using a dotted path "Game.Player_Decks.1". Instead you need to individually address each property within each object.
JObjects are effectively an array of named properties, JObject implements IDictionary<string, JToken?> so as long as each child element is also a JObject then you can use the string index to reference the element in the next level.
JObject game = (JObject)rss["Game"];
JObject decks = (JObject)game["Player_Decks"];
JObject channel = (JObject)decks["1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
The following syntax should also work:
JObject channel = rss["Game"]["Player_Decks"]["1"] as JObject;
Also, have you considered using a Json Array instead of properties named 1, 2, etc. like so:
{
"Game": {
"Player_Decks": [
{
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
{
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
],
"Deck_NoCards": {}
}
}
and accessed as:
JObject rss = JObject.Parse(final);
JObject game = (JObject)rss["Game"];
JArray decks = (JArray)game["Player_Decks"];
JObject deck1 = (JObject)decks[0];

JSON Data to dynamic (Anonymous type) conversion

I'm having trouble converting JSON data to a dynamic type definition. I've looked at JObject, JsonConvert serialize/deserialize and nothing works. The closest thing to making this work is JsonConvert.DeserializeAnonymousType but this requires a definition that matches the JSON. In my case, the JSON is quite complicated so I really need to convert an instance of the JSON to a fully anonymous, dynamic type.
dynamic rawjson = #"{ 'tags': { 'abcd' : '12345' },'properties': { 'desired': { 'PropOne' : '2345', 'PropTwo' : '6789' } } }";
#region reference object
dynamic reference = new
{
SomeName = $"xxxx",
initialTwin = new
{
tags = new { abcd = 12345 },
properties = new
{
desired = new
{
PropOne = "2345",
PropTwo = "6789"
}
}
}
};
#endregion
dynamic anonobject = JsonConvert.DeserializeAnonymousType(rawjson, reference.initialTwin);
dynamic testobject = new
{
SomeName = $"xxxx",
initialTwin = $"{anonobject}"
};
I need the "testobject" in the code above to look exactly like the "reference" object. Using the DesializeAnonymousType gets me very close but the definition would be very hard to create and maintain.
How can I get the same results working from an instance of JSON data without typing the definition for DeserializeAnonyousType? Is that possible?
I have tested the way below and it worked for me:
var anonobject = JsonConvert.DeserializeObject<ExpandoObject>(rawjson);
dynamic testobject = new
{
SomeName = $"xxxx",
initialTwin = anonobject
};
But since this is a dynamic object, you need to know the properties you may want to use.
Example:
Console.WriteLine(testobject.initialTwin.tags.abcd);

Is it possible to add fields with invalid characters to a .net AnonymousType?

I'm trying to send a JSON message to facebook that they call a game.achievement but I wanted to create the object using an AnonymousType before Posting. The problem is one of the fields is "game:points" (with the colon). As you can see I've used the # prefix for the object field but it doesn't work for the game:points field. It gets underlined in red and won't compile.
var paramsJson = new
{
privacy = new { value = "ALL_FRIENDS" },
#object = new
{
app_id = "my app id",
type = "game.achievement",
title = "Test",
#"game:points" = 100,
description = "Test",
image = "img.png"
}
};
I've tried many varieties of #, double quotes etc. Is it possible or do I need to just use a StringBuilder for this?
Why don't you just use a dictionary?
var postData = new Dictionary<string, object>
{
{"game:points", 100}
}
Presumably you're going to have to serialize your object to Post it regardless of how it's constructed. Serializing this to JSON would result in the same structure. Alternatively, just do as other's have suggested and create a class for your payload. You can then use Newtonsoft to indicate alternative names for serialization.
public class GameAchievement
{
[JsonProperty("game:points")]
public int Points {get; set;}
}

Convert JSON String to JSON Object c#

I have this String stored in my database:
str = "{ "context_name": { "lower_bound": "value", "upper_bound": "value", "values": [ "value1", "valueN" ] } }"
This string is already in the JSON format but I want to convert it into a JObject or JSON Object.
JObject json = new JObject();
I tried the json = (JObject)str; cast but it didn't work so how can I do it?
JObject defines method Parse for this:
JObject json = JObject.Parse(str);
You might want to refer to Json.NET documentation.
if you don't want or need a typed object try:
using Newtonsoft.Json;
// ...
dynamic json = JsonConvert.DeserializeObject(str);
or try for a typed object try:
using Newtonsoft.Json;
// single
Foo foo = JsonConvert.DeserializeObject<Foo>(str);
// or as a list
List<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(str);
This works
string str = "{ 'context_name': { 'lower_bound': 'value', 'pper_bound': 'value', 'values': [ 'value1', 'valueN' ] } }";
JavaScriptSerializer j = new JavaScriptSerializer();
object a = j.Deserialize(str, typeof(object));
there's an interesting way to achive another goal which is to have a strongly type class base on json with a very powerfull tools that i used few days ago for first time to translate tradedoubler json result into classes
Is a simple tool: copy your json source paste and in few second you will have a strongly typed class json oriented .
In this manner you will use these classes which is more powerful and simply to use.
You can try like following:
string output = JsonConvert.SerializeObject(jsonStr);
This works for me using JsonConvert
var result = JsonConvert.DeserializeObject<Class>(responseString);
If your JSon string has "" double quote instead of a single quote ' and has \n as a indicator of a next line then you need to remove it because that's not a proper JSon string, example as shown below:
SomeClass dna = new SomeClass ();
string response = wc.DownloadString(url);
string strRemSlash = response.Replace("\"", "\'");
string strRemNline = strRemSlash.Replace("\n", " ");
// Time to desrialize it to convert it into an object class.
dna = JsonConvert.DeserializeObject<SomeClass>(#strRemNline);
In a situation where you are retrieving a list of objects of a certain entity from your api, your response string may look like this:
[{"id":1,"nome":"eeee","username":null,"email":null},{"id":2,"nome":"eeee","username":null,"email":null},{"id":3,"nome":"Ricardo","username":null,"email":null}]
In this situation you may want an array of Jason objects and cycle through them to populate your c# variable. I've done like so:
var httpResponse = await Http.GetAsync($"api/{entidadeSelecionada}");
List<List<string[]>> Valores = new();
if (httpResponse.IsSuccessStatusCode)
{
//totalPagesQuantity = int.Parse(httpResponse.Headers.GetValues("pagesQuantity").FirstOrDefault());
//Aqui tenho que colocar um try para o caso de ser retornado um objecto vazio
var responseString = await httpResponse.Content.ReadAsStringAsync();
JArray array = JArray.Parse(responseString);
foreach (JObject objx in array.Children<JObject>())
{
List<string[]> ls = new();
foreach (JProperty singleProp in objx.Properties())
{
if (!singleProp.Name.Contains("_xyz"))
{
string[] val = new string[2];
val[0] = singleProp.Name;
val[1] = singleProp.Value.ToString();
ls.Add(val);
}
}
Valores.Add(ls);
}
}
return Valores;
I achieved this solution by the #Andrei answer.
This does't work in case of the JObject this works for the simple json format data. I have tried my data of the below json format data to deserialize in the type but didn't get the response.
For this Json
{
"Customer": {
"id": "Shell",
"Installations": [
{
"id": "Shell.Bangalore",
"Stations": [
{
"id": "Shell.Bangalore.BTM",
"Pumps": [
{
"id": "Shell.Bangalore.BTM.pump1"
},
{
"id": "Shell.Bangalore.BTM.pump2"
},
{
"id": "Shell.Bangalore.BTM.pump3"
}
]
},
{
"id": "Shell.Bangalore.Madiwala",
"Pumps": [
{
"id": "Shell.Bangalore.Madiwala.pump4"
},
{
"id": "Shell.Bangalore.Madiwala.pump5"
}
]
}
]
}
]
}
}
string result = await resp.Content.ReadAsStringAsync();
List<ListView11> _Resp = JsonConvert.DeserializeObject<List<ListView11>>(result);
//List<ListView11> _objList = new List<ListView11>((IEnumerable<ListView11>)_Resp);
IList usll = _Resp.Select(a => a.lttsdata).ToList();
// List<ListViewClass> _objList = new List<ListViewClass>((IEnumerable<ListViewClass>)_Resp);
//IList usll = _objList.OrderBy(a=> a.ReqID).ToList();
Lv.ItemsSource = usll;

Class Object with Dynamic Structure

Hi Am trying to parse a json Object with Help of C# DataContractJsonSerializer And this is what json may look like
{"user_id":"121","Q1":"question 1","Q2":"question 2","Q3":"question 3"}
And Number of question can be 200- 500,
So I dont want to make a DataContract with 500 Variables to parse this Json, So I was thinking if there is a way where i can call the constructor or something for this class object with a number parameter like this if there are Q1 - Q30 in jSon
Objectparse new_object = new Objectparse(30);
Which will create variables Q1 to Q30 at runtime? and parse the Json
You could use JavaScriptSerializer:
var json = #"{""user_id"":""121"",""Q1"":""question 1"",""Q2"":""question 2"",""Q3"":""question 3""}";
var serializer = new JavaScriptSerializer();
dynamic result = serializer.DeserializeObject(json);
Console.WriteLine(result["Q1"]);
Console.WriteLine(result["Q2"]);
...
and if you are using an older version of .NET than 4.0 and cannot use the dynamic feature you could do this:
var json = #"{""user_id"":""121"",""Q1"":""question 1"",""Q2"":""question 2"",""Q3"":""question 3""}";
var serializer = new JavaScriptSerializer();
var result = (IDictionary<string, object>)serializer.DeserializeObject(json);
Console.WriteLine(result["Q1"]);
Console.WriteLine(result["Q2"]);
...
But let me point out that this is an extremely poor JSON design. The person that designed this class was probably not aware of javascript arrays:
{
"user_id": "121",
"questions": [
{
"key": "Q1",
"value": "question 1"
},
{
"key": "Q2",
"value": "question 2"
},
{
"key": "Q3",
"value": "question 3"
}
]
}
Which could now be serialized into a strongly typed object containing a collections of questions.

Categories