Deserializing JSON object array to List<MyOwnClass> - c#

I'm trying to read this JSON array:
[{"name":"lc_cash","slot":1,"info":"","type":"item","amount":591},{"name":"advancedlockpick","slot":2,"info":[],"type":"item","amount":19}]
This is my code:
File Inventory.cs
class Item {
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("slot")]
public int Slot { get; set; }
[JsonProperty("info")]
public object Info { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("amount")]
public int Amount { get; set; }
}
class Inventory
{
public List<Item> Item { get; set; }
}
File Form1.cs
Inventory inventory = new Inventory();
inventory = JsonSerializer.Deserialize<Inventory>(players.Inventory);
I'm getting this error:
System.Text.Json.JsonException: 'The JSON value could not be converted to Inventory. Path: $ | LineNumber: 0 | BytePositionInLine: 1.'
How can I read this correctly?
EDIT: testing with stackoverflow answers:
Main code:
List<Item> items = new List<Item>();
items = JsonSerializer.Deserialize<List<Item>>(players.Inventory);
Item class:
class Item {
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("slot")]
public int Slot { get; set; }
[JsonProperty("info")]
public string Info { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("amount")]
public int Amount { get; set; }
}
Result: It's not throwing exception anymore but reading only 0 and nill

you will have to fix your json, one of the property info has value string, another has array. you have to select something one, null for example
var jsonParsed = JArray.Parse(json);
foreach (var item in jsonParsed)
{
if (((JObject)item)["info"].GetType().Name == "JArray"
|| ((JObject)item)["info"].GetType().Name == "JValue")
((JObject)item)["info"] = null;
}
List<Item> items = jsonParsed.ToObject<List<Item>>();
result
[
{
"name": "lc_cash",
"slot": 1,
"info": null,
"type": "item",
"amount": 591
},
{
"name": "advancedlockpick",
"slot": 2,
"info": null,
"type": "item",
"amount": 19
}
]
UPDATE
if you sometimes have
"info":{"food":30,"thirst":30}
it is better to change info property to this
[JsonProperty("info")]
public Dictionary<string,int> Info { get; set; }
or a little more complicated
[JsonProperty("info")]
public Info Info { get; set; }
public class Info
{
[JsonProperty("food")]
public int Food {get; set;}
[JsonProperty("thirst")]
public int Thirst {get; set;}
}

as long as the information here is right, you gave us a json array string.
the inventory is an object with an array, so the simple solution will be this:
Inventory inventory = new Inventory();
inventory.Item = JsonSerializer.Deserialize<List<Item>>(players.Inventory);
important to mention that since Item is a list, you should use plural name

Related

Filter JSON Array based on element value in C#

I have this JSON by using: var root = JToken.Parse(myInputJson);
{{
"results": [
{
"orderId": "A123456789",
"genId": 3,
"invoiceId": "001",
"locId": "D07",
"group": "",
"assignedUserId": "TEST",
"billTo": 66537,
"shipTo": 66537,
"shipToName": "CONSTRUCTION TEST",
"pickCount": "1",
"shipBy": "UPS",
"isFromMultipleZones": false,
"taskState": "Assigned",
"boxes": []
},
{
"orderId": "B987654321",
"genId": 3,
"invoiceId": "001",
"locId": "D08",
"group": "",
"assignedUserId": "",
"billTo": 66537,
"shipTo": 66537,
"shipToName": "CONSTRUCTION TEST",
"pickCount": "4",
"shipBy": "UPS",
"isFromMultipleZones": false,
"taskState": "Assigned",
"boxes": []
}
]
}
What I need to is to get all the elements between the braces where the orderId = "B987654321".
After researching I have got this far but is not producing what I need:
var root = JToken.Parse(myInputJson);
var values = root.Where(t => (string)t["orderId"] == "B987654321").ToList();
I think I am close, can anyone see where my mistake is?
You forgot to index root by "results":
var root = JToken.Parse(text);
var values = root["results"].Where(t =>(string)t["orderId"] == "B987654321");
Also, your example JSON is badly formatted. If you delete the very first opening brace ({) it works
To get an order as JToken you can use this code
var results = JObject.Parse(json).SelectToken("results").ToArray();
var jsonOrder = results.First(o => o.SelectToken("orderId").ToString() == "B987654321");
but since you are using c# , it is much easier and safer to use an instance of Order class instead of JToken
Order order=jsonOrder.ToObject<Order>();
Order class
public partial class Order
{
[JsonProperty("orderId")]
public string OrderId { get; set; }
[JsonProperty("genId")]
public long GenId { get; set; }
[JsonProperty("invoiceId")]
public string InvoiceId { get; set; }
[JsonProperty("locId")]
public string LocId { get; set; }
[JsonProperty("group")]
public string Group { get; set; }
[JsonProperty("assignedUserId")]
public string AssignedUserId { get; set; }
[JsonProperty("billTo")]
public long BillTo { get; set; }
[JsonProperty("shipTo")]
public long ShipTo { get; set; }
[JsonProperty("shipToName")]
public string ShipToName { get; set; }
[JsonProperty("pickCount")]
[JsonConverter(typeof(ParseStringConverter))]
public long PickCount { get; set; }
[JsonProperty("shipBy")]
public string ShipBy { get; set; }
[JsonProperty("isFromMultipleZones")]
public bool IsFromMultipleZones { get; set; }
[JsonProperty("taskState")]
public string TaskState { get; set; }
[JsonProperty("boxes")]
public List<object> Boxes { get; set; }
}
But it is much easier to deseialize the whole json as net object instead of parsing. You can use linq to get any data.
List<Order> orders =JsonConvert.DeserializeObject<Root>(json).Orders;
Order order = orders.First(o => o.OrderId == "B987654321");
Root class
public partial class Root
{
[JsonProperty("results")]
public List<Order> Orders { get; set; }
}

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

Deserialise JSON iin C# using system.text.json with complex property name

I am trying to deserialise JSON files that have been created by a third party tool.
The files contain a property that can look like the below:
"RECIPE": [{
"ctPoint_0": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_1": {
"endTemperature": 30,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_2": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 30
},
"pointCount": 3,
"type": "CyclicTemp"
}, {
"cycles": 2,
"type": "Repeat"
}, {
"cycles": 1,
"duration": {
"days": 0,
"hours": 0
},
}]
I am using system.text.json to deserialise:
newProgram = JsonSerializer.Deserialize<Program>(jsonString, options);
Extract of my Program class:
public class Program
{
public IList<Recipe> RECIPE { get; set; }
}
Recipe and cyclic_data struct:
public struct Cyclic_Data
{
public float endTemperature { get; set; }
public float hours { get; set; }
public float startTemperature { get; set; }
}
public struct Recipe
{
public int cycles { get; set; }
// Would like to use this
public IList<Cyclic_Data> ctPoints { get; set; }
// this deserialises ok but obviously only to hardcoded limit
public Cyclic_Data ctPoint_0 { get; set; }
public Cyclic_Data ctPoint_1 { get; set; }
public Cyclic_Data ctPoint_2 { get; set; }
public Cyclic_Data ctPoint_3 { get; set; }
public Cyclic_Data ctPoint_4 { get; set; }
public Cyclic_Data ctPoint_5 { get; set; }
public Cyclic_Data ctPoint_6 { get; set; }
public Cyclic_Data ctPoint_7 { get; set; }
public Cyclic_Data ctPoint_8 { get; set; }
public Cyclic_Data ctPoint_9 { get; set; }
public Cyclic_Data ctPoint_10 { get; set; }
public Duration duration { get; set;}
public string type { get; set; }
public float temperature { get; set; }
public int pointCount { get; set; }
}
As per the comments, if I have a number of discrete variables of type Cyclic_Data e.g. ctPoint_0 then this successfully deserialises, however as this list could theoretically be arbitrarily large it would be a nonsense to try to declare all possible property names.
I would really like to use an IList to read in all ctPoint_X values but am struggling to find a way to do so. I was looking at the newton soft implementation instead and wondering whether [JsonProperty("name")] could be used with RegEx to solve this but could not find any successful example done in this way.
How can I deserialise this in a sensible manner?
EDIT:
I am currently looking at a custom JsonNamingPolicy to rename any property name matching a RegEx "^ctPoint_[0-9]+$" to ctPoints, will let you know if this succeeds, please comment if this is doomed to fail or if there is a better way..
EDIT 2:
I tried the method outlined above but it didn't work as the correct JSON for a list of items doesn't have the name at beginning of each item, however this started me thinking about the problem differently. What I ended up doing was some simple string replacements before the deserialisation. This worked fine :)
int location;
location = newText.IndexOf("\"ctPoint_0\":");
newText = newText.Replace("\"ctPoint_0\":", "\"ctPoints\": [");
if (location > 0)
{ int lastloc;
for (int i = 1; i < 999999; i++)
{
string nextString = "\"ctPoint_" + i.ToString() + "\": ";
lastloc = location;
location = newText.IndexOf(nextString);
newText = newText.Replace(nextString, "");
if (location == -1)
{
location = newText.IndexOf("}", lastloc);
newText = newText.Insert(location+1, "]");
break;
}
}
}
Thanks
You can try Dictionary<string, object> and check the object type during runtime
Here are the models required for this scenario
public class CtPoint
{
public int endTemperature { get; set; }
public double hours { get; set; }
public int startTemperature { get; set; }
}
public class Duration
{
public int days { get; set; }
public int hours { get; set; }
}
Here is the sample code to Deserialize the JSON using System.Text.Json.JsonSerializer
var results = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string,object>>>(json);
foreach (var model in results)
{
foreach(var item in model)
{
if (item.Key.Contains("ctPoint"))
{
var ctPoint = System.Text.Json.JsonSerializer.Deserialize<CtPoint>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {ctPoint.hours} {ctPoint.startTemperature} {ctPoint.endTemperature}");
}
else if (item.Key.Contains("duration"))
{
var duration = System.Text.Json.JsonSerializer.Deserialize<Duration>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {duration.days} {duration.hours}");
}
else
{
Console.WriteLine($"{item.Key}- {item.Value.ToString()}");
}
}
}
Output
ctPoint_0- 0,0799999982118607 25 25
ctPoint_1- 0,0799999982118607 25 30
ctPoint_2- 0,0799999982118607 30 25
pointCount- 3
type- CyclicTemp
cycles- 2
type- Repeat
cycles- 1
duration- 0 0

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

Parsing JSON using Newtonsoft.JSON

I have a JSON string as follows:
[{
"ID":"1",
"title":"New Product Launch",
"fro":"Vitamin D",
"summary":"New Vitamin D prodcut",
"type":"image",
"link":"http:\/\/www.foo.in\/upload\/image\/1.png",
"detail":"13-11-2013",
"fileSize":23763
},
{
"ID":"2",
"title":"New Product Launch",
"fro":"Vitamin D",
"summary":"New Vitamin D prodcut",
"type":"image",
"link":"http:\/\/www.foo.in\/upload\/image\/1.png",
"detail":"13-11-2013",
"fileSize":23763
}]
My code for parsing is as follows:
AnnouncementListObject resultsJSON = JsonConvert.DeserializeObject<AnnouncementListObject>(json); //line1
using (AnnouncementDataContext context = new AnnouncementDataContext(Con_String))
{
AnnouncementData alData = new AnnouncementData();
alData.announcementID = int.Parse(resultsJSON.ID);
.
.
.
.
context.AnnouncementData.InsertOnSubmit(alData);
context.SubmitChanges();
}
EDIT:
public class AnnouncementListObject
{
public string ID { get; set; }
public string title { get; set; }
public string fro { get; set; }
public string summary { get; set; }
public string type { get; set; }
public string link { get; set; }
public string detail { get; set; }
public object fileSize { get; set; }
}
But it throws error on line 1 where I deserialize the JSON data. I want to store this multiple data rows in database. I cannot use foreach loop here as JSON data is not enclosed under root node. Any help on how should I go about?
Try deserializing to a list like so
var resultsJSON = JsonConvert.DeserializeObject<List<AnnouncementListObject>>(json); //line1
You're dealing with an array of JSON objects, but you're trying to cast it as a single object.

Categories