Deserialize JSON Object into Class - c#

I'm having a little trouble deserializing a JSON object to a class (using JSON.NET), and hoping someone can point me in the right direction. Below is a snippet of code I'm trying, and been testing at dotnetfiddle
Here's a sample of the JSON:
{
"`LCA0001": {
"23225007190002": "1",
"23249206670003": "1",
"01365100070018": "5"
},
"`LCA0003": {
"23331406670018": "1",
"24942506670004": "1"
},
"`LCA0005": {
"01365100070018": "19"
}
}
I'm trying to use this code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string json = "{\"`LCA0001\": {\"23225007190002\": \"1\",\"23249206670003\": \"1\",\"01365100070018\": \"5\"},\"`LCA0003\": {\"23331406670018\": \"1\",\"24942506670004\": \"1\"},\"`LCA0005\": {\"01365100070018\": \"19\"}}";
Console.WriteLine(json);
Console.WriteLine();
//This works
Console.Write("Deserialize without class");
var root = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, int>>>(json);
foreach (var locationKvp in root)
{
foreach (var skuKvp in locationKvp.Value)
{
Console.WriteLine("location: " + locationKvp.Key + ", sku: " + skuKvp.Key + ", qty: " + skuKvp.Value);
}
}
//Why doesn't this work?
Console.Write("\nDeserialize with class");
var root2 = JsonConvert.DeserializeObject<InventoryLocations>(json);
foreach (var locationKvp in root2.InventoryLocation)
{
foreach (var skuKvp in locationKvp.Value)
{
Console.WriteLine("location: " + locationKvp.Key + ", sku: " + skuKvp.Key + ", qty: " + skuKvp.Value);
}
}
}
}
class InventoryLocations
{
public Dictionary<Location, Dictionary<Sku, Qty>> InventoryLocation { get; set; }
}
public class Location
{
public string location { get; set; }
}
public class Sku
{
public string sku { get; set; }
}
public class Qty
{
public int qty { get; set; }
}
Is there a reason why deserializing into a Class doesn't work? Am I just defining the classes incorrectly?

I see two problems here: one is using classes as the dictionary keys - the JSON has simple strings there (and cannot have anything else really), so that won't work.
The second problem is that deserialization of JSON to classes works by matching keys to properties - so it converts something like
{
"prop1": "value1",
"prop2": "value2"
}
to an instance of:
public class MyClass {
public string prop1 { get; set; }
public string prop2 { get; set; }
}
In your case this cannot work because in your JSON all keys are not valid property names. You have to stick with the deserialization to a dictionary

One of the ways to generate the classes from JSON is using Visual Studio.
Navigate to Edit -> Paste Special -> Paste JSON As Classes. For posted JSON in question, following classes are generated.
public class Rootobject
{
public LCA0001 LCA0001 { get; set; }
public LCA0003 LCA0003 { get; set; }
public LCA0005 LCA0005 { get; set; }
}
public class LCA0001
{
public string _23225007190002 { get; set; }
public string _23249206670003 { get; set; }
public string _01365100070018 { get; set; }
}
public class LCA0003
{
public string _23331406670018 { get; set; }
public string _24942506670004 { get; set; }
}
public class LCA0005
{
public string _01365100070018 { get; set; }
}

In addition to MiMo's answer, you can use a ContractResolver to serialize/deserialize Dictionaries within classes.
Here's a working example of your code in dotnetfiddle.
Note the serialized Json with the contract resolver is different than the original json. It must be serialized using this contract resolver in order to deserialize with it as well.
I pulled the contract resolver from this StackOverflow question, if you need any more clarification.

Related

Deserialize Json Nested Object to a class level property instead of a class object [duplicate]

This question already has answers here:
Can I specify a path in an attribute to map a property in my class to a child property in my JSON?
(7 answers)
Closed 3 years ago.
Deserializing json Nested Objects to class properties instead of a class object
well I just want json deserializer do deserialize directrly to my FlatClassModel instead of serializing it to the ClassModel and then map it by hand
look at the following code for example
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
// assume we have a given json
var Json = #"{
'ClassLevelProperty': 'Class Level Values',
'NestedModel': {
'FirstNestedProperty': 'First Nested value',
'AnotherNestedProperty': 'Another Nested Value'
}
}";
var classModel = JsonConvert.DeserializeObject<ClassModel>(Json);
var flatclassModel = JsonConvert.DeserializeObject<FlatClassModel>(Json);
Console.Write(classModel.ClassLevelProperty + " ... " + classModel.NestedModel.FirstNestedProperty + " ... " + classModel.NestedModel.AnotherNestedProperty);
Console.WriteLine();
Console.Write(flatclassModel.ClassLevelProperty + " ... " + flatclassModel.FirstNestedProperty + " ... " + flatclassModel.AnotherNestedProperty);
}
}
class ClassModel
{
public string ClassLevelProperty { get; set; }
public NestedModel NestedModel { get; set; }
}
public class NestedModel
{
public string FirstNestedProperty { get; set; }
public string AnotherNestedProperty { get; set; }
}
public class FlatClassModel
{
public string ClassLevelProperty { get; set; }
public string FirstNestedProperty { get; set; }
public string AnotherNestedProperty { get; set; }
}
Tip: A handy way to try the code goto https://try.dot.net/ paste and run
I just want json deserializer do deserialize directrly to my FlatClassModel
Why? The model must match the JSON in order to successfully deserialize. Imagine AnotherNestedProperty to exist on the root level and on a deeper level, which one do you want to be populated? And why?
So either create a conversion from one type to the other:
var flattened = new FlatClassModel
{
ClassLevelProperty = classModel.ClassLevelProperty,
FirstNestedProperty = classModel.NestedModel.FirstNestedProperty,
AnotherNestedProperty = classModel.AnotherNestedProperty,
};
Or create read-only properties:
public class ClassModel
{
public string ClassLevelProperty { get; set; }
public string FirstNestedProperty => NestedModel.FirstNestedProperty;
public string AnotherNestedProperty => NestedModel.AnotherNestedProperty;
public NestedModel NestedModel { get; set; }
}

c# data pull from json - can not detect the "-" sign between words

string json_index = '"libraries": [
{
"name": "test1",
"natives": {
"windows": "natives-windows"
},
"downloads": {
"classifiers": {
"natives-windows": {
"url": "http://test1.com/"
}
}
}
},
{
"name": "test2",
"natives": {
"windows": "natives-windows"
},
"downloads": {
"classifiers": {
"natives-windows": {
"url": "http://test2.com/"
}
}
}
}
]';
dynamic jsonObj = JsonConvert.DeserializeObject(json_index);
foreach (var obj in jsonObj.libraries)
{
label1.Text += "\n" + obj.downloads.classifiers.natives-windows.url; // error here
}
Can not detect the "-" sign between words.
I actually thought that:
string nativeswindows = obj.natives.windows;
label1.Text += "\n" + obj.downloads.classifiers.nativeswindows.url;
but it did not work
How can I get the "url" in "natives-windows" ?
I am using Newtonsoft JSON.
you try:
label1.Text += "\n" + obj.downloads.classifiers["natives-windows"].url;
I found this link: Parsing JSON w/ # at sign symbol in it (arobase)
Hope it will help you!
So there's a few steps to this.
First you need to define a concrete class to represent your JSON. I've done this using http://json2csharp.com, with the output being here:
public class Natives
{
public string windows { get; set; }
}
public class NativesWindows
{
public string url { get; set; }
}
public class Classifiers
{
public NativesWindows __invalid_name__natives-windows { get; set; }
}
public class Downloads
{
public Classifiers classifiers { get; set; }
}
public class Library
{
public string name { get; set; }
public Natives natives { get; set; }
public Downloads downloads { get; set; }
}
public class RootObject
{
public List<Library> libraries { get; set; }
}
Your problematic field has been flagged up by this tool too, seen here:
public NativesWindows __invalid_name__natives-windows { get; set; }
So we need a way to assign the JSON Key/Value pair to a valid C# field. We can does this using Attributes.
For this field in particular, we can use the JsonProperty attribute to take in the JSON property name and assign it to a C# field on your new concrete class. This looks like:
[JsonProperty("native-windows")]
public NativesWindows NativeWindowsObj { get; set; }
You can put that into your new concrete class, and then use the following to deserialize to that type:
Natives jsonObj = JsonConvert.DeserializeObject<Natives>(json_index);
This is telling Newtonsoft:
I have a property name native-windows.
I'm deserializing my JSON to this specific class.
The invalid C# identified native-windows matches a JsonProperty I've specified in my class, assign the value to that matching attribute.
Return the full, deserialized object.

C# Json how to deserialize something with a key that could be any kind of int

I'm working on a Xamarin App, and I use Newtonsoft for Json.
But I'm having trouble with processing some data that I get back.
{
"ok": true,
"payment-methods": [
{
"id": "39sahf92ka9s02",
"type": "ideal",
"options": {
"issuers": {
99: "Test Issuer"
}
}
}
],
}
I don't know how to get to the Test Issuer, because the Key value could be any integer.
A Dictionary makes a lot of sense to use, but then I get the following exception: "System.NullReferenceException: Object reference not set to an instance of an object. json"
I have the following as Model:
[JsonObject(MemberSerialization.OptIn)]
public class PaymentOptions
{
[JsonProperty("ok")]
public Boolean OK { get; set; }
[JsonProperty("payment-methods")]
public List<PaymentMethods> PaymentMethods { get; set; }
}
public class PaymentMethods
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("options")]
public Options Options { get; set; }
}
public class Options
{
[JsonProperty("issuers")]
public IDictionary<int, string> Issuers { get; set; }
}
I deserialize the Json through the following:
var deserializedGetPaymentOptions = JsonConvert.DeserializeObject<Models.PaymentMethods>(await responseGetPaymentOptions.Content.ReadAsStringAsync());
And after that I try to read it by using it in a foreach loop:
foreach (KeyValuePair<int, string> issuerFromDict in deserializedGetPaymentOptions.Options.Issuers)
Have you tried with 99 as string in the json representation ?
...
"issuers": {
"99": "Test Issuer"
}
...
You should let newtonsoft deals with the conversion to int.
I fixed it by doing the following:
var deserializedGetPaymentOptions = JsonConvert.DeserializeObject<Models.PaymentOptions>(await responseGetPaymentOptions.Content.ReadAsStringAsync());
foreach (var desPayOp in deserializedGetPaymentOptions.PaymentMethods) {
Debug.WriteLine("start foreach");
foreach (KeyValuePair<int, string> issuerFromDict in desPayOp.Options.Issuers)
{
Debug.WriteLine(issuerFromDict.Key.ToString() + " : " + issuerFromDict.Value);
}
}
I now deserialize it from PaymentOptions instead of PaymentMethods, then loop through the List and after that through the dictionary.

Cannot deserialize the JSON array

I have Json like below:
[
{
"name": "ts.DatumVon",
"value": "29.10.2015"
},
{
"name": "ts.Von",
"value": "8:00"
},
{
"name": "ts.Bis",
"value": "16:30"
}
]
for this class:
public class TSInfo
{
public TimeSaver ts { get; set; }
[Display(Name = "Status")]
public TSStatus tsStatus { get; set; }
[Display(Name = "Typ")]
public TSTyp tsTyp { get; set; }
public TSAuswahlSteps step { get; set; }
}
How to deserialize this Json string in controller method?
EDIT:
I hope that clarifies it.
public class TimeSaver
{
public DateTime DatumVon { get; set; }
public TimeSpan Von { get; set; }
public TimeSpan Bis { get; set; }
}
I tried something like this:
string tsi = [{"name":"ts.DatumVon","value":"29.10.2015"},{"name":"ts.Von","value":"8:00"},{"name":"ts.Bis","value":"16:30"}]
var dict = JsonConvert.DeserializeObject<List<Dictionary<String,String>>(tsi);
The JSON you provided is a list of dictionaries. So you can deserialize it (using NewtonSoft.Json) like this:
string json = "your json";
var result = JsonConvert.Deserialize<List<Dictionary<String,String>>(json);
How you map the result to your class is up to you.
EDIT the above makes no sense. Sorry for that.
Well, your JSON gave me some headache but I think I fixed it.
The JSON is an array of KeyValuePairs. Every pair describes an attribute of your TimeSaver class. The array as an whole describes the complete class. I don't know of an easy way to convert this JSON to a C# class. What complicates the problem even more is the fact that every attribute has some sort of namespace prefix: ts. The final complication is the date format. That's not a format that's recognized automatically.
My solution converts the JSON to a new JSON describing a TimeSaver object. This new JSON is then deserialized using JsonConvert.
One issue still remains: the TimeSaver.DateVon has become a string.
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string tsi = "[{\"name\":\"ts.DatumVon\",\"value\":\"29.10.2015\"},{\"name\":\"ts.Von\",\"value\":\"8:00\"},{\"name\":\"ts.Bis\",\"value\":\"16:30\"}]";
var attributes = JsonConvert.DeserializeObject<List<NameValuePair>>(tsi);
attributes = attributes
.Select(item => new NameValuePair { Name = item.Name.Replace("ts.", ""), Value = item.Value })
.ToList();
var newJson = "{" + String.Join(",", attributes.Select(item => String.Format("\"{0}\":\"{1}\"", item.Name, item.Value))) + "}";
Console.WriteLine(newJson);
var ts = JsonConvert.DeserializeObject<TimeSaver>(newJson);
Console.WriteLine(ts.DatumVon);
Console.WriteLine(ts.Von);
Console.WriteLine(ts.Bis);
}
}
public class NameValuePair
{
public string Name { get; set; }
public string Value { get; set; }
}
public class TimeSaver
{
public String DatumVon { get; set; }
public TimeSpan Von { get; set; }
public TimeSpan Bis { get; set; }
}

json newtonsoft : Deserialize Object containing a list of string

I have the following issue with this json :
{
"EVTS": {
"EVT": [
{ "ID": "123456",
"KEY1" : "somekey",
"CATEG": [
"cat1",
"cat2",
"cat3"
]
}
]}
}
and this c# class:
public class myClass{
public string ID { get; set; }
public string KEY1 { get; set; }
public list<string> CATEG { get; set; }
}
public class ESObject1
{
[JsonProperty("EVT")]
public List<myClass> EVT { get; set; }
}
public class ESObject0
{
[JsonProperty("EVTS")]
public ESObject1 EVTS { get; set; }
}
}
here i call the deserializer :
ESObject0 globalobject = JsonConvert.DeserializeObject<ESObject0>(json);
But this last code doesnt work, i throws this exception : System.ArgumentException: Could not cast or convert from System.String to System.Collections.Generic.List1[System.String].`
Instead of list<string> i used string [] and only string nothing seems to work.
how can i deserialize this object correctly please.
Thank you.
There doesn't seem to be any apparent problem wit hyour code as this working example illustrates:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
public class myClass
{
public string ID { get; set; }
public string KEY1 { get; set; }
public List<string> CATEG { get; set; }
}
public class ESObject1
{
[JsonProperty("EVT")]
public List<myClass> EVT { get; set; }
}
public class ESObject0
{
[JsonProperty("EVTS")]
public ESObject1 EVTS { get; set; }
}
class Program
{
static void Main()
{
string json =
#"{
""EVTS"": {
""EVT"": [
{
""ID"": ""123456"",
""KEY1"": ""somekey"",
""CATEG"": [
""cat1"",
""cat2"",
""cat3""
]
}
]
}
}";
ESObject0 globalobject = JsonConvert.DeserializeObject<ESObject0>(json);
foreach (string item in globalobject.EVTS.EVT[0].CATEG)
{
Console.WriteLine(item);
}
}
}
Maybe you just fed a wrong json value to the deserializer which doesn't look like as the one shown in your question. By the way, the one shown i nyour question is invalid JSON as you are missing a , after KEY1 property declaration.
UPDATE:
Now that you have shown your real JSON (coming from http://donnees.ville.quebec.qc.ca/Handler.ashx?id=69&f=JSON) it appears that there's a row where CATEG is not an array of strings but a simple string:
""CATEG"": ""Conférence""
Now that's a pretty bad design because they are mixing arrays and simple properties. I am afraid that in order to deal with this situation you will need to use JObjects and extract the information you need by testing the actual underlying type.
For example:
var obj = JObject.Parse(json);
var events = (JArray)obj["EVTS"]["EVT"];
foreach (JObject evt in events)
{
var categories = evt["CATEG"];
if (categories is JArray)
{
// you've got a list of strings so you can loop through them
string[] cats = ((JArray)categories)
.Select(x => x.Value<string>())
.ToArray();
}
else
{
// you've got a simple string
string cat = categories.Value<string>();
}
}
I have done this many times with many many headaches. My advice is take the json output and use a tool similar to this to write your class for you (http://json2csharp.com/).
Then go over any nullable variables and add nullable type (ex. using int? for int) where needed.

Categories