Cannot get value from nested json - c#

I'm deserializing a JSON object into a class that I created using json2csharp. Once deserialized, I cannot access the nested values of this object. The error I get is this:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
This is the class I created;
public class Ticker
{
public List<object> error { get; set; }
public Result result { get; set; }
public class Result
{
public XXBTZCAD XBTCAD { get; set; }
public class XXBTZCAD
{
public List<string> a { get; set; }
public List<string> b { get; set; }
public List<string> c { get; set; }
public List<string> v { get; set; }
public List<string> p { get; set; }
public List<int> t { get; set; }
public List<string> l { get; set; }
public List<string> h { get; set; }
public string o { get; set; }
}
}
}
Here is the JSON string, at the time of this writing:
{
"error": [
],
"result": {
"XXBTZCAD": {
"a": [
"4776.10000",
"8",
"8.000"
],
"b": [
"4773.90000",
"1",
"1.000"
],
"c": [
"4776.20000",
"0.02510294"
],
"v": [
"4.85183508",
"61.15237421"
],
"p": [
"4775.02293",
"4767.92898"
],
"t": [
126,
608
],
"l": [
"4756.70000",
"4720.60000"
],
"h": [
"4780.00000",
"4783.30000"
],
"o": "4776.40000"
}
}
}
This is the code that deserializes and attempts to display the first value of List a
private async void GetKraken(object sender, RoutedEventArgs e)
{
var client = new RestClient();
IRestResponse response;
Ticker BTCCADTicker = new Ticker();
client.BaseUrl = new Uri("https://api.kraken.com/0/public/Ticker?pair=XBTCAD");
var request = new RestRequest();
response = await client.ExecuteTaskAsync(request);
BTCCADTicker = JsonConvert.DeserializeObject<Ticker>(response.Content);
MessageBox.Show(BTCCADTicker.result.XBTCAD.a[0]);
}
I would expect to see a value around 4700 to be returned, but I'm getting the error above instead. What gives? Any help is appreciated.

You haven't defined XXBTZCAD in your model. You've called it XBTCAD by mistake. Fixed it looks like this:
public class Ticker
{
public List<object> error { get; set; }
public Result result { get; set; }
public class Result
{
public XXBTZCAD XXBTZCAD { get; set; }
public class XXBTZCAD
{
public List<string> a { get; set; }
public List<string> b { get; set; }
public List<string> c { get; set; }
public List<string> v { get; set; }
public List<string> p { get; set; }
public List<int> t { get; set; }
public List<string> l { get; set; }
public List<string> h { get; set; }
public string o { get; set; }
}
}
}
I see now that this is the same name as the nested class. I'd recommend the simple solution of not nesting your classes:
public class Ticker
{
public List<object> error { get; set; }
public Result result { get; set; }
}
public class Result
{
public XXBTZCAD XXBTZCAD { get; set; }
}
public class XXBTZCAD
{
public List<string> a { get; set; }
public List<string> b { get; set; }
public List<string> c { get; set; }
public List<string> v { get; set; }
public List<string> p { get; set; }
public List<int> t { get; set; }
public List<string> l { get; set; }
public List<string> h { get; set; }
public string o { get; set; }
}
If you really want to nest them, simply rename class XXBTZCAD to something else. It's the property name that's important for deserialization, not the type name.

I suggest copy your JSON and in Visual Studio :
Edit > Paste Special > Parse JSON As Classes
public class Ticker
{
public object[] error { get; set; }
public Result result { get; set; }
}
public class Result
{
public XXBTZCAD XXBTZCAD { get; set; }
}
public class XXBTZCAD
{
public string[] a { get; set; }
public string[] b { get; set; }
public string[] c { get; set; }
public string[] v { get; set; }
public string[] p { get; set; }
public int[] t { get; set; }
public string[] l { get; set; }
public string[] h { get; set; }
public string o { get; set; }
}
and you can use this method to get the result :
public static async Task<string> GetKraken()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.kraken.com/0/public/Ticker?pair=XBTCAD");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
and then use the method and convert it to get actual object:
var ticker = JsonConvert.DeserializeObject<Ticker>(GetKraken().Result);

Related

Problem Deserializing JSON to objects in C#

I have the below response from the API in a console application written in C#:
{
"d": {
"results": [
{
"__metadata": {
"id": "123",
"uri": "456",
"type": "789"
},
"PERNR": "1",
"USRID": "2"
},
{
"__metadata": {
"id": "159",
"uri": "951",
"type": "753"
},
"PERNR": "4",
"USRID": "6"
}
]
}
}
And used the below code to deserialize:
public class d
{
public results results { get; set; }
}
public class results
{
public string PERNR { get; set; }
public string USRID { get; set; }
public __metadata __metadata { get; set; }
}
public class __metadata
{
public string id { get; set;}
public string uri { get; set; }
public string type { get; set; }
}
var serilizer = new JavaScriptSerializer();
d output = serilizer.Deserialize<d>(response.Content);
But the result is null. Is there any problem in the definition of the classes?
The properties should start with a capital letter, to match the case of the properties in the JSON response. Change the class definitions as follows:
public class D
{
public Results[] results { get; set; }
}
public class Results
{
public string PERNR { get; set; }
public string USRID { get; set; }
public Metadata __metadata { get; set; }
}
public class Metadata
{
public string id { get; set;}
public string uri { get; set; }
public string type { get; set; }
}
Change deserialize line to:
var serilizer = new JavaScriptSerializer();
D output = serilizer.Deserialize<D>(response.Content);
The issue is results is an array in your json, where in your class, it is an object. Change it to
public class d
{
public Result[] results { get; set; }
}
If you use a JSON to C# converter like json2csharp or Visual Studio's Paste JSON As Classes you'll get :
public class Root
{
public D d { get; set; }
}
public class D
{
public List<Result> results { get; set; }
}
public class Metadata
{
public string id { get; set; }
public string uri { get; set; }
public string type { get; set; }
}
public class Result
{
public Metadata __metadata { get; set; }
public string PERNR { get; set; }
public string USRID { get; set; }
}
There are two important differences :
The JSON document contains a root element with an attribute named d, not a D object
D.results is a collection of Result objects, not a single object

Why different results when deserializing objects?

I noticed that I would get different results when deserializing objects different ways. I must have missed something but couldn't figure out what.
Here is the json:
{
"content_version": "1",
"date_created": "2020-10-06T13:52:15.288Z",
"date_updated": "2020-10-06T13:54:24.325Z",
"content": {
"EN": {
"name_full": {
"text": "Test"
},
"name_short": {
"text": "TEST"
}
}
},
"tools": {
"car": true,
"truck": true,
"fleet": {
"use": true,
"languages": [
{
"fileName": "file1.json",
"name": {
"text": "English"
}
}
]
}
}
}
The following are the classes that I generated using a tool:
public class Root
{
public string content_version { get; set; }
public DateTime date_created { get; set; }
public DateTime date_updated { get; set; }
public ContentRootObject content { get; set; }
public Tools tools { get; set; }
}
public class ContentRootObject
{
[JsonProperty(PropertyName = "content")]
public Dictionary<string, ContentItem> DataItems { get; set; }
}
public class ContentItem
{
public NameFull name_full { get; set; }
public NameShort name_short { get; set; }
}
public class Tools
{
public bool car { get; set; }
public bool truck { get; set; }
public Fleet fleet { get; set; }
}
public class NameFull
{
public string text { get; set; }
}
public class NameShort
{
public string text { get; set; }
}
public class EN
{
public NameFull name_full { get; set; }
public NameShort name_short { get; set; }
}
public class Name
{
public string text { get; set; }
}
public class Language
{
public string fileName { get; set; }
public Name name { get; set; }
}
public class Fleet
{
public bool use { get; set; }
public List<Language> languages { get; set; }
}
and here is the code that I tried for deserializing :
var objTool = Newtonsoft.Json.JsonConvert.DeserializeObject<Tools>(json);
var objRoot = Newtonsoft.Json.JsonConvert.DeserializeObject<Root>(json);
var objContent = Newtonsoft.Json.JsonConvert.DeserializeObject<ContentRootObject>(json)
and here is what I got for each of the objects:
objTool: 'fleet' was returned as null in 'tools'
objRoot: the DataItems of 'content' was null.
objContent: got an error saying "Unexpected character encountered while parsing value: {. Path 'content.EN', line 1, position 146."
Although I can just deserialize the whole thing, I only need objTool and objContent and I was wondering what I did wrong in the above code? Thanks!
The issue is that the class that you have as a wrapper for the dictionary is not represented in the JSON. It'll deserialize the dictionary if you change the root object to this:
public class Root
{
public string content_version { get; set; }
public DateTime date_created { get; set; }
public DateTime date_updated { get; set; }
public Dictionary<string, ContentItem> content { get; set; }
public Tools tools { get; set; }
}

Object reference not set to an instance of an object error when im getting the value json

i am trying to get the "definitions" inside the "senses" array how ever there's an object reference error. I created a class and i can only get the values up to "results" array only e.g(id,language,text and word) but i cant access the "lexicalEntries","entries" and "senses" arrays and there values because of the error.
This is my JSON
"id":"bird",
"metadata":{
"operation":"retrieve",
"provider":"Oxford University Press",
"schema":"RetrieveEntry"
},
"results":[
{
"id":"bird",
"language":"en-gb",
"lexicalEntries":[
{
"entries":[
{
"senses":[
{
"definitions":[
"a warm-blooded egg-laying vertebrate animal distinguished by the possession of feathers, wings, a beak, and typically by being able to fly."
],
"id":"m_en_gbus0097360.006",
"subsenses":[]
},
{
"definitions":[
"a person of a specified kind or character"
],
"id":"m_en_gbus0097360.014"
},
{
"definitions":[
"a young woman or a girlfriend."
],
"id":"m_en_gbus0097360.016"
}
]
}
],
"language":"en-gb",
"lexicalCategory":{
"id":"noun",
"text":"Noun"
},
"text":"bird"
}
],
"type":"headword",
"word":"bird"
}
],
"word":"bird"
}
this is my class
class WordDefinition
{
public RootObject rootObject { get; set; }
public Metadata metadata { get; set; }
public List<Result> results { get; set; }
public List<LexicalEntry> lexicalEntries { get; set; }
public List<Entry> entries { get; set; }
public List<Sens> senses { get; set; }
public List<Subsens> subsenses { get; set; }
public LexicalCategory lexicalCategory { get; set; }
public class Metadata
{
public string operation { get; set; }
public string provider { get; set; }
public string schema { get; set; }
}
public class Subsens
{
public List<string> definitions { get; set; }
public string id { get; set; }
}
public class Sens
{
public List<string> definitions { get; set; }
public string id { get; set; }
public List<Subsens> subsenses { get; set; }
}
public class Entry
{
public List<Sens> senses { get; set; }
}
public class LexicalCategory
{
public string id { get; set; }
public string text { get; set; }
}
public class LexicalEntry
{
public List<Entry> entries { get; set; }
public string language { get; set; }
public LexicalCategory lexicalCategory { get; set; }
public string text { get; set; }
}
public class Result
{
public string id { get; set; }
public string language { get; set; }
public List<LexicalEntry> lexicalEntries { get; set; }
public string type { get; set; }
public string word { get; set; }
}
public class RootObject
{
public string id { get; set; }
public Metadata metadata { get; set; }
public List<Result> results { get; set; }
public string word { get; set; }
}
}
and
var test = JsonConvert.DeserializeObject<WordDefinition>(jsonResponse);
foreach(var testing in test.senses)
{
MessageBox.Show(testing.definitions[0].ToString());
}
I expect the output must be results.definitions[0]. but there's an error:
Object reference not set to an instance of an object error
...in json
There are a few things going on here.
1) The JSON isn't valid, it should start with an { character, e.g.:
{
"id": "bird",
"metadata": {
"operation": "retrieve",
"provider": "Oxford University Press",
"schema": "RetrieveEntry"
},
"results": [
{
"id": "bird",
"language": "en-gb",
"lexicalEntries": [
{
"entries": [
{
"senses": [
{
"definitions": [
"a warm-blooded egg-laying vertebrate animal distinguished by the possession of feathers, wings, a beak, and typically by being able to fly."
],
"id": "m_en_gbus0097360.006",
"subsenses": []
},
{
"definitions": [
"a person of a specified kind or character"
],
"id": "m_en_gbus0097360.014"
},
{
"definitions": [
"a young woman or a girlfriend."
],
"id": "m_en_gbus0097360.016"
}
]
}
],
"language": "en-gb",
"lexicalCategory": {
"id": "noun",
"text": "Noun"
},
"text": "bird"
}
],
"type": "headword",
"word": "bird"
}
],
"word": "bird"
}
2) The collections should be initialized in the class definitions, e.g.:
class WordDefinition
{
public RootObject rootObject { get; set; }
public Metadata metadata { get; set; }
public List<Result> results { get; set; } = new List<Result>();
public List<LexicalEntry> lexicalEntries { get; set; } = new List<LexicalEntry>();
public List<Entry> entries { get; set; } = new List<Entry>();
public List<Sens> senses { get; set; } = new List<Sens>();
public List<Subsens> subsenses { get; set; } = new List<Subsens>();
public LexicalCategory lexicalCategory { get; set; }
public class Metadata
{
public string operation { get; set; }
public string provider { get; set; }
public string schema { get; set; }
}
public class Subsens
{
public List<string> definitions { get; set; } = new List<string>();
public string id { get; set; }
}
public class Sens
{
public List<string> definitions { get; set; } = new List<string>();
public string id { get; set; }
public List<Subsens> subsenses { get; set; } = new List<Subsens>();
}
public class Entry
{
public List<Sens> senses { get; set; } = new List<Sens>();
}
public class LexicalCategory
{
public string id { get; set; }
public string text { get; set; }
}
public class LexicalEntry
{
public List<Entry> entries { get; set; } = new List<Entry>();
public string language { get; set; }
public LexicalCategory lexicalCategory { get; set; }
public string text { get; set; }
}
public class Result
{
public string id { get; set; }
public string language { get; set; }
public List<LexicalEntry> lexicalEntries { get; set; } = new List<LexicalEntry>();
public string type { get; set; }
public string word { get; set; }
}
public class RootObject
{
public string id { get; set; }
public Metadata metadata { get; set; }
public List<Result> results { get; set; } = new List<Result>();
public string word { get; set; }
}
}
And 3) The JSON doesn't have a senses element at the root level. Maybe you intended test.results[0].lexicalEntries[0].entries[0].senses instead? e.g.:
var test = JsonConvert.DeserializeObject<WordDefinition>(jsonResponse);
foreach (var testing in test.results[0].lexicalEntries[0].entries[0].senses)
{
MessageBox.Show(testing.definitions[0].ToString());
}

Unable to Parsing nested Json file in C#

I have Json format response from a API call and I want to map the data from the response to each varibales.
Json format
{
"success": true,
"data": {
"students": [
{
"Admission_date": "2018-05-01",
"Name": "Sree",
"Branch": "Electronics",
"Semester": "2",
"HOD": "Mahesh",
},
{
"Admission_date": "2018-05-01",
"Name": "Naresh",
"Branch": "Electronics",
"Semester": "2",
"HOD": "Mahesh",
}
],
"remaining": 0
}
}
I have tried to parse the JSON response and then to load the value through for each. But I'm not able to achieve the solution.
JObject jsonparsing1 = JObject.Parse(str4); //str4;- Json value
var token1 = (JArray)jsonparsing1.SelectToken("data");
var token2 = (JArray)jsonparsing1.SelectToken("data[0]Students");
JArray abc = JsonConvert.DeserializeObject<JArray>(token2.ToString());
foreach (var test in abc)
{
String Admission_date=test["Admission_date"];
String Name=test["Name"];
String Branch=test["Branch"];
String Semester=test["Semester"];
String HOD=test["HOD"];
String remaining=test["remaining"];
}
Expected result
String Admission_date=Admission_date
String Name=Name
String Branch=Branch
String Semester=Semester
String HOD=HOD
String remaining=remaining
Could anyone please help me on this?
I think you can use this sample:
public class JsonData
{
public bool success { get; set; }
public Data data { get; set; }
}
public class Data
{
public Data()
{
this.students = new List<Student>();
}
public List<Student> students { get; set; }
public int remaining { get; set; }
}
public class Student
{
public string Admission_date { get; set; }
public string Name { get; set; }
public string Branch { get; set; }
public string Semester { get; set; }
public string HOD { get; set; }
}
And then:
JsonData abc = JsonConvert.DeserializeObject<JsonData>(token2.ToString());
I will do this way!
public class Student
{
public string Admission_date { get; set; }
public string Name { get; set; }
public string Branch { get; set; }
public string Semester { get; set; }
public string HOD { get; set; }
}
public class Data
{
public List<Student> students { get; set; }
public int remaining { get; set; }
}
public class RootObject
{
public bool success { get; set; }
public Data data { get; set; }
}
and in C# Code Just use only below line:
var obj = JsonConvert.DeserializeObject<RootObject>("{ \"success\": true,\"data\": {\"students\": [{ \"Admission_date\": \"2018-05-01\",\"Name\": \"Sree\",\"Branch\":\"Electronics\",\"Semester\": \"2\",\"HOD\": \"Mahesh\",}],\"remaining\": 0}}");
use
foreach(var item in obj.data.students)
{
// Access Admission_date etc.
string name = item.Name;
}
dotnetfiddle

RESTful service and JSON array

I have a .NET Core 1.x Web API project and I am trying to accept an array on HTTP post, but I have been unable to get this working. I have validated the following JSON
{
"LogEntry": [{
"a": 1238976,
"b": "test",
"c": "sub test",
"d": "some syb system comp",
"e": 1234,
"f": "my category",
"g": "my event name",
"h": "my sub event",
"i": "user def 1",
"j": "7/22/2008 12:11:04 PM",
"k": 45,
"l": 65,
"n": "Chris",
"o": "C:\\temp\\",
"p": 1234567890,
"q": 84,
"r": "eeeee stuff",
"s": "ddddd stuff",
"t": 90210
}]
}
I have a model class so I need each array item to be added to a list of the model type. This is where I am stuck. I have only been able to get this working with a single entry not in an array. My C# for that scenario is:
[HttpPost]
public string Post([FromBody] JObject test)
{
var result = JsonConvert.DeserializeObject<EventManagerLogEntry>(test.ToString());
return "wootwoot";
}
Any direction on how I can loop through each array in my jObject and have it added to a list of type would be very helpful.
Class Definition
public class EventManagerLogEntry
{
public int a { get; set; }
public string b { get; set; }
public string c { get; set; }
public string d { get; set; }
public int e { get; set; }
public string f { get; set; }
public string g { get; set; }
public string h { get; set; }
public string i { get; set; }
public string j { get; set; }
public int k { get; set; }
public int l { get; set; }
public string m { get; set; }
public string n { get; set; }
public int o { get; set; }
public int p { get; set; }
public string q { get; set; }
public string r { get; set; }
public int s { get; set; }
}
UPDATE
I tried several different methods and this seems to be working for me.
[HttpPost]
public HttpResponseMessage Post([FromBody] JArray test)
{
var list = JsonConvert.DeserializeObject<List<EventManagerLogEntry>>(test.ToString());
foreach (EventManagerLogEntry x in list)
{
//_context.EventManagerLogEntry.Attach(x);
//_context.SaveChanges();
}
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Use this model to deserialize your json
public class Log
{
public List<Dictionary<string,string>> LogEntry { get; set; }
}
var log = JsonConvert.DeserializeObject<Log>(json);
You can also use linq
var jObj = JObject.Parse(json);
var listOfDict = jObj["LogEntry"]
.Select(x => x.Cast<JProperty>()
.ToDictionary(p => p.Name, p => p.Value))
.ToList();
Just change your model to this.
public class EventManagerLogEntry
{
[JsonProperty("LogEntry")]
public List<Node> LogEntries { get; set; }
}
public class Node
{
public int a { get; set; }
public string b { get; set; }
public string c { get; set; }
public string d { get; set; }
public int e { get; set; }
public string f { get; set; }
public string g { get; set; }
public string h { get; set; }
public string i { get; set; }
public string j { get; set; }
public int k { get; set; }
public int l { get; set; }
public string m { get; set; }
public string n { get; set; }
public int o { get; set; }
public int p { get; set; }
public string q { get; set; }
public string r { get; set; }
public int s { get; set; }
}
And simple deserialize object.
var obj = JsonConvert.DeserializeObject<EventManagerLogEntry>(yourjson);
There are a couple improvements you can make to get this working. First thing is that you should not need to deserialize your json manually.
public class Value
{
public String Name { get; set; }
}
...
[HttpPost("one")]
public void Post([FromBody] Value value)
{
Console.WriteLine("got one");
}
[HttpPost("many")]
public void Post([FromBody] Value[] value)
{
Console.WriteLine("got many");
}
you can use the class definition in the POST methods to automatically get the objects from the json.
Second you can do one of two things:
Post only the array json to the server and use an array
Create a new model that encapsulates your list as #L.B has mentioned.
Below are the json data sent to the above routes that work.
One
{ "name" : "test" }
Many
[{ "name" : "test" }]

Categories

Resources