Deserialize json object with dynamic items in C# - c#

I've got the following json document:
{
"name": "bert",
"Bikes": {
"Bike1": {
"value": 1000,
"type": "Trek"
},
"Bike2": {
"value": 2000,
"type": "Canyon"
}
}
}
With potentially other bikes like Bike3...BikeN. I want to deserialize to C# objects. Problem is that in the deserialization step the bikes data is completely lost, resulting in a null Bikes collection.
Code to reproduce:
[Test]
public void FirstCityJsonParsingTest()
{
var file = #"./testdata/test.json";
var json = File.ReadAllText(file);
var res = JsonConvert.DeserializeObject<Person>(json);
Assert.IsTrue(res.Name == "bert");
// next line is failing, because res.Bikes is null...
Assert.IsTrue(res.Bikes.Count == 2);
}
public class Bike
{
public string Id { get; set; }
public int Value { get; set; }
public string Type { get; set; }
}
public class Person
{
public string Name { get; set; }
public List<Bike> Bikes { get; set; }
}
To fix this problem a change in the used model is necessary. But what change is needed here to fill the bikes data correctly?
Note: Changing the input document is not an option (as it's a spec)

Your code structure is not reflecting your json. Common approach to deserializing json with dynamic property names is to use Dictionary<string, ...> (supported both by Json.NET and System.Text.Json). Try the following:
public class Bike
{
public int Value { get; set; }
public string Type { get; set; }
}
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, Bike> Bikes { get; set; }
}
Person.Bikes should be changed to Dictionary<string, Bike> (also Bike.Id property is not needed) cause Bikes json element is not an array but object.

Related

How to deserialize root JSON dynamic property name in C#? [duplicate]

I've got the following json document:
{
"name": "bert",
"Bikes": {
"Bike1": {
"value": 1000,
"type": "Trek"
},
"Bike2": {
"value": 2000,
"type": "Canyon"
}
}
}
With potentially other bikes like Bike3...BikeN. I want to deserialize to C# objects. Problem is that in the deserialization step the bikes data is completely lost, resulting in a null Bikes collection.
Code to reproduce:
[Test]
public void FirstCityJsonParsingTest()
{
var file = #"./testdata/test.json";
var json = File.ReadAllText(file);
var res = JsonConvert.DeserializeObject<Person>(json);
Assert.IsTrue(res.Name == "bert");
// next line is failing, because res.Bikes is null...
Assert.IsTrue(res.Bikes.Count == 2);
}
public class Bike
{
public string Id { get; set; }
public int Value { get; set; }
public string Type { get; set; }
}
public class Person
{
public string Name { get; set; }
public List<Bike> Bikes { get; set; }
}
To fix this problem a change in the used model is necessary. But what change is needed here to fill the bikes data correctly?
Note: Changing the input document is not an option (as it's a spec)
Your code structure is not reflecting your json. Common approach to deserializing json with dynamic property names is to use Dictionary<string, ...> (supported both by Json.NET and System.Text.Json). Try the following:
public class Bike
{
public int Value { get; set; }
public string Type { get; set; }
}
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, Bike> Bikes { get; set; }
}
Person.Bikes should be changed to Dictionary<string, Bike> (also Bike.Id property is not needed) cause Bikes json element is not an array but object.

How can I convert a json string to a json array using Newtonsoft?

I am using this code to read a json file firstSession.json and display it on a label.
var assembly = typeof(ScenarioPage).GetTypeInfo().Assembly;
string jsonFileName = "firstSession.json";
Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
using (var reader = new StreamReader(stream))
{
var json = reader.ReadToEnd(); //json string
var data = JsonConvert.DeserializeObject<SessionModel>(json);
foreach (SessionModel scenario in data)
{
scenarioName.Text = scenario.title;
break;
}
scenarioName.Text = data.title; // scenarioName is the name of the label
}
SessionModel.cs looks like:
public class SessionModel : IEnumerable
{
public int block { get; set; }
public string name { get; set; }
public string title { get; set; }
public int numberMissing { get; set; }
public string word1 { get; set; }
public string word2 { get; set; }
public string statement1 { get; set; }
public string statement2 { get; set; }
public string question { get; set; }
public string positive { get; set; } // positive answer (yes or no)
public string negative { get; set; } // negative answer (yes or no)
public string answer { get; set; } // positive or negative
public string type { get; set; }
public string format { get; set; }
public string immersion { get; set; }
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
The beginning of my json is:
{
"firstSession": [
{
"block": 1,
"name": "mark",
"title": "mark's house",
"numberMissing": 1,
"word1": "distracted",
"word2": "None",
"statement1": "string 1",
"statement2": "None",
"question": "question",
"positive": "No",
"negative": "Yes",
"answer": "Positive",
"type": "Social",
"format": "Visual",
"immersion": "picture"
},
I am getting a Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object into type "MyProject.SessionModel" because the type requires a JSON array to deserialize correctly. To fix this error either change the JSON to a JSON array or change the deserialized type so that it is a normal .NET type that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'firstSession', line 2, position 17.
How can I convert the json string to a json array? Or make one of the other modifications the debugger suggests?
you need to create a wrapper class (json2csharp.com will help you do this)
public class Root {
public List<SessionModel> firstSession { get; set; }
}
then
var data = JsonConvert.DeserializeObject<Root>(json);
data.firstSession will be a List<SessionModel>
Create a new Class and have firstSession as List of SessionModel.
public class Sessions
{
public List<SessionModel> firstSession { get; set; }
}
Remove IEnumerable from the SessionModel
public class SessionModel
{
public int block { get; set; }
public string name { get; set; }
public string title { get; set; }
}
Change thedeserialization part as follows
var data = JsonConvert.DeserializeObject(line);
foreach (SessionModel scenario in data.firstSession)
{
//Here you can get each sessionModel object
Console.WriteLine(scenario.answer);
}

Dynamic json property deserialize

I'm having difficulties figuring out how to deserialize a json, that has a dynamic property (for example - UserRequest::567) the property name can be any value and the UserRequest object contains other json properties that are of interest to me
I tired writing a class and I don't know what to do with that property. What are the best practices for coping with a problem like this?
{
"objects": {
"UserRequest::567": {
"code": 0,
"message": "created",
"class": "UserRequest",
"key": "567",
"fields": {
"ref": "R-000567",
"org_id": "4"
}
}
}
}
The question is what are the best practices to read through this kind of a json string?
Thank you
To Deserialize this using Newtonsoft.Json, here are the classes:
public class CreateRequest
{
public long code { get;set; }
public string message { get; set; }
[JsonProperty("class")]
public string class1 { get; set; }
public string key { get; set; }
public Fields fields { get; set; }
}
public class Fields
{
[JsonProperty("ref")]
public string refe { get; set; }
public string org_id { get; set; }
}
public class Root
{
public Dictionary<string, CreateRequest> objects { get; set; }
//The 'string' key in the dictionary is the 'UserRequest::567'
}
Then to Deserialize use:
var x = Newtonsoft.Json.JsonConvert.DeserializeObject<Root>(jsonObject).objects.Values;

Json.net deserialization is returning an empty object

I'm using the code below for serialization.
var json = JsonConvert.SerializeObject(new { summary = summary });
summary is a custom object of type SplunkDataModel:
public class SplunkDataModel
{
public SplunkDataModel() {}
public string Category { get; set; }
public int FailureCount { get; set; }
public Dictionary<string, SplunkError> FailureEntity { get; set; }
public Dictionary<string, string> JobInfo { get; set; }
public string JobStatus { get; set; }
public int SuccessCount { get; set; }
public List<string> SuccessEntity { get; set; }
public int TotalCount { get; set; }
}
Serialization results in the JSON below:
{
"summary": {
"Category": "category",
"JobStatus": "Failure",
"JobInfo": {
"Course processing failed": ""
},
"TotalCount": 0,
"SuccessCount": 0,
"FailureCount": 0,
"FailureEntity": {},
"SuccessEntity": []
}
}
Now, for unit testing purposes, I need to deserialize it, but the code below is returning an object with empty values. Where am I going wrong?
var deserialized = JsonConvert.DeserializeObject<SplunkDataModel>(contents);
On my side, it was because I had no public setter for my properties.
Instead of having
public class MyClass
{
public int FileId { get; }
}
I should have
public class MyClass
{
public int FileId { get; set; }
}
silly mistake that cost me hours....
When you serialized your SplunkDataModel to JSON, you wrapped it in an object with a summary property. Hence, when you deserialize the JSON back to objects, you need to use the same structure. There are several ways to go about it; they all achieve the same result.
Declare a class to represent the root level of the JSON and deserialize into that:
public class RootObject
{
public SplunkDataModel Summary { get; set; }
}
Then:
var deserialized = JsonConvert.DeserializeObject<RootObject>(contents).Summary;
Or, deserialize by example to an instance of an anonymous type, then retrieve your object from the result:
var anonExample = new { summary = new SplunkDataModel() };
var deserialized = JsonConvert.DeserializeAnonymousType(contents, anonExample).summary;
Or, deserialize to a JObject, then materialize your object from that:
JObject obj = JObject.Parse(contents);
var deserialized = obj["summary"].ToObject<SplunkDataModel>();

read multiple Json data from webservice

i have a web service that returns a Json string.
my problem is that i have difficulties to read it
i tried with:
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
string jsonData = reader.ReadToEnd();
var myobj = jsSerializer.Deserialize<List<CinfoRichiesta>>(jsonData);
but how can i get values from "students" and "locations"?
with javascript i used :" var j = jQuery.parseJSON(msg.d);" but i think with c# code would be different
this is an example of string:
{"Questions":{
"id":"2",
"BOOK":"3",
"students":{
"class":"3",
"theme","43"
},
"locations":{
"h":"0",
"L":"3"
}
}
}
First off, your JSON isn't valid so thats the first problem you have. You can verify this at http://jsonlint.com/ for example.
i have currently fixed this in the following way:
{
"Questions": {
"id": "2",
"BOOK": "3",
"students": {
"class": "3",
"theme": "na",
"43": "na"
},
"locations": {
"h": "0",
"L": "3"
}
}
}
Second your class should be correct, with the current JSON this should look something like this
public class Rootobject
{
public Questions Questions { get; set; }
}
public class Questions
{
public string id { get; set; }
public string BOOK { get; set; }
public Students students { get; set; }
public Locations locations { get; set; }
}
public class Students
{
public string _class { get; set; }
public string theme { get; set; }
public string _43 { get; set; }
}
public class Locations
{
public string h { get; set; }
public string L { get; set; }
}
After this you can deserialize it like this
var myobj = jsSerializer.Deserialize<List<Rootobject>>(jsonData);
And then you can get the information like this
myobj.Questions.students._class
You're deserializing to a collection of type CinfoRichiesta, which should hold a property value for students and locations.
Assuming that your JSON is correctly formatted and your class definition is suitable for the response (I recommend double checking it by pasting the entire response string into json2csharp.com)
Once that's all validated, you should be able to see the students and locations collections internally like so:
foreach(Question q in myobj)
{
Console.WriteLine(q.students.class)
}
which should give you the result of 3.
edit
I think your main question is why you're unable to access the properties of students and locations. Make sure Students is its own class as such:
public class Students
{
public int class { get; set; }
public int theme { get; set; }
}
and your locations class should be:
public class Locations
{
public int h { get; set; }
public int l { get; set; }
}
You should then have a questions class that instaniates both students and locations, as such:
public class Questions
{
public int id { get; set; }
public int book { get; set; }
public Student students { get; set; }
public Locations locations { get; set; }
}
When working with JSON deserialization, it's important that your object property names (ie class) match the response string in terms of case. So If you wrote it as public int Theme, it won't directly map.
Slightly annoying in terms of coding standards, but hey ho :-)

Categories