C# Json.net - Deserialise JSON object and access nested values - c#

I'm writing here because I think I used all resources I could get. There must be something terribly wrong with my abstraction/approach because I cannot
make it work properly. Task is quite simple - I need to iterate through nested list(??) generated from json input(or maybe I'm doing it wrong from the scratch).
Using jquery with this json works great but this time I need to process data on the server side.
I got json input(example extract below):
{
"services":[
{
"service_status":"CRITICAL",
"service_host":{
"host_status":2,
"host_address":"192.168.1.12",
"host_name":"test1app_srv",
"host_problem_has_been_acknowledged":0,
"host_has_comments":0,
"host_notifications_enabled":1,
"host_checks_enabled":1,
"host_is_flapping":0,
"host_scheduled_downtime_depth":0,
"host_notes_url":"",
"host_action_url":"",
"host_icon_image":"server.gif"
},
"service_description":"test1app_srv",
"service_problem_has_been_acknowledged":0,
"service_has_comments":0,
"service_accept_passive_service_checks":1,
"service_notifications_enabled":1,
"service_checks_enabled":1,
"service_is_flapping":0,
"service_scheduled_downtime_depth":0,
"service_notes_url":"",
"service_action_url":"",
"service_icon_image":"services.gif",
"service_state_duration":" 0d 0h 2m 7s",
"service_last_check":"04-27-2013 23:49:55",
"service_current_attempt":1,
"service_max_attempts":1,
"service_plugin_output":"CRITICAL - Throughput : Threshold '600' failed for value 720"
},
{}
]
}
from which, using http://json2csharp.com/ I've generated c# classes:
public class ServiceHost
{
public int host_status { get; set; }
public string host_address { get; set; }
public string host_name { get; set; }
public int host_problem_has_been_acknowledged { get; set; }
public int host_has_comments { get; set; }
public int host_notifications_enabled { get; set; }
public int host_checks_enabled { get; set; }
public int host_is_flapping { get; set; }
public int host_scheduled_downtime_depth { get; set; }
public string host_notes_url { get; set; }
public string host_action_url { get; set; }
public string host_icon_image { get; set; }
}
public class Service
{
public string service_status { get; set; }
public ServiceHost service_host { get; set; }
public string service_description { get; set; }
public int service_problem_has_been_acknowledged { get; set; }
public int service_has_comments { get; set; }
public int service_accept_passive_service_checks { get; set; }
public int service_notifications_enabled { get; set; }
public int service_checks_enabled { get; set; }
public int service_is_flapping { get; set; }
public int service_scheduled_downtime_depth { get; set; }
public string service_notes_url { get; set; }
public string service_action_url { get; set; }
public string service_icon_image { get; set; }
public string service_state_duration { get; set; }
public string service_last_check { get; set; }
public int service_current_attempt { get; set; }
public int service_max_attempts { get; set; }
public string service_plugin_output { get; set; }
}
public class NagiosRootObject
{
public List<Service> services { get; set; }
}
I managed to get the NagiosRootObject.services content but I cannot access values from Service.service_host.
I focused on an approach utilizing
NagiosRootObject obj = JsonConvert.DeserializeObject<NagiosRootObject>(json);
I have all above and I'm using Json.NET from http://json.codeplex.com.
I have tried hints from
Deserializing JSON object into a C# list
Deserialize JSON array(or list) in C#
C# - How to implement IEnumerator on a class
Deserialize Json to Class that implements Ienumerable in Asp.net
and few related but witho no luck.
Knowing that there is so many tutorials and not being able to make use of it makes me really sad..
Help would be appreciated. This post is the last resort for this task... I need serious tips. Thank You

Using json.NET the following code works: (after putting your json in a file called 'json.txt')
using (var reader = File.OpenText("json.txt"))
{
var ser = JsonSerializer.Create(null);
var jReader = new JsonTextReader(reader);
var grp = ser.Deserialize<NagiosRootObject>(jReader);
}
However, the list is populated by two objects, and in the 2nd one all the values are null. This is because you have an empty element {} in your json.
Edit: Your code works just as well in my test, so no need to change it.

Have you tried:
var obj = new JavaScriptSerializer().Deserialize<NagiosRootObject>(jsonString);

If you want to parse this json in server then it is better to parse this json into XML and utilize that xml to traverse. In server side coding xml traversing is easy. Especially in C#.
Convert the json into XMl or wise versa using newtonsoft dll. The code to parse json to XMl is
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(json);
Dpwnload the dll from the link
http://json.codeplex.com/
I hope this will help you.

Related

First time using NewtonSoft (JsonConvert.DeserializeObject<>() for deserializing JSON versus System.Text.Json (JsonSerializer.Deserialize<>()

​Using VS 2019, Dot Net Core, Azure Function. HttpTrigger.
I've worked with JSON files previously in .Net Desktop and Server app dev. So, don't know what's happening in Azure and with Newtonsoft. When I try and dump the value of wht.YourName.last, I get the error,
Object reference not set to an instance of an object
which confuses me because in my other programming with System.Text.Json, if I have a class model for a JSON file structure that has a child, the usual function call I use, which is JsonSerializer.Deserialize<jsonclass>(jsonstring), it has no problem setting up the child of the parent parent (reference below, class structure).
Is there a difference between the two function implementations, JsonConvert.DeserializeObject and JsonSerializer.Deserialize?
All of the code samples I've seen seem for Newtonsoft's method seem straight forward as its counterpart in dot net, which doesn't require me to have to do any pre-initalization of the NameBlock class/object.
Hope I explained that well enough considering my brain is kind of fried learning Azure.
Here is my deserialization code using Newtonsoft's method:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
WebhookTest wht = JsonConvert.DeserializeObject<WebhookTest>(requestBody);
Raw dump of httprequest.Body:
{
"FormID":"1081011",
"UniqueID":"178165183",
"support_request":"",
"your_name":{
"first":"Testy",
"last":"Tester"
},
"email":"jxxxx#gxxxcxxxaxxxxxxxx.com",
"phone":"(111) 867-5309",
"upload_a_file_optional":"",
"request_details":"Testing latest revision of Azure function that deserializes JSON data into a class object."
}
This is what my class structure looks like:
public class NameBlock
{
public string first { get; set; }
public string last { get; set; }
}
public class WebhookTest
{
public string FormID { get; set; }
public string UniqueID { get; set; }
public string SupportRequest { get; set; }
public NameBlock YourName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
[JsonProperty("Uploadafile(optional)")]
public string UploadafileOptional { get; set; }
public string RequestDetails { get; set; }
}
The reason for the error Object reference not set to an instance of an object is the code can't find wht.YourName(because wht.YourName is null). Please change your class structure to:
public class NameBlock
{
public string first { get; set; }
public string last { get; set; }
}
public class WebhookTest
{
public string FormID { get; set; }
public string UniqueID { get; set; }
public string SupportRequest { get; set; }
[JsonProperty(PropertyName = "your_name")]
public NameBlock YourName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
[JsonProperty("Uploadafile(optional)")]
public string UploadafileOptional { get; set; }
public string RequestDetails { get; set; }
}
Just add a line [JsonProperty(PropertyName = "your_name")]
By the way:
When we use System.Text.Json, it will relate your_name(in request json) with YourName(in class structure) automatically according to hump law. But when we use Newtonsoft.Json, it can't do it. So it can't relate your_name with YourName. We need to add [JsonProperty(PropertyName = "your_name")] to let the code know how to relate the two properties.

nested json deserialization - need another set of eyes

I have been trying to get this json to deserialize for two days now using RestSharp. I have gone through the RestSharp github site, looked at countless examples, and spent much time here on Stack Overflow to try and find the answer to no avail. My code had previously worked perfectly but the vendor changed their API version and I was forced to do an update to keep using the application for my legal practice. My json is as follows(client info has been removed and replaced with generic info):
{
"data":[
{
"id":1035117666,
"client":
{
"id":905422394,
"name":"client1"
},
"display_number":"11-00012",
"description":"General",
"practice_area":
{
"id":4269978,
"name":"Business"
},
"status":"Open",
"open_date":"2011-12-14",
"close_date":null,
"billing_method":"hourly"
},
{
"id":1035117768,
"client":
{
"id":905422506,
"name":"client2"
},
"display_number":"12-00037",
"description":"HOA",
"practice_area":
{
"id":4269978,
"name":"Business"
},
"status":"Open",
"open_date":"2012-08-07",
"close_date":null,
"billing_method":"hourly"
}
],
"meta":
{
"paging":
{
"next":"https://app.goclio.com/api/v4/matters.json?fields=id%2C+client%7Bid%2C+name%7D%2C+display_number%2C+description%2C+practice_area%7Bid%2C+name%7D%2C+status%2C+open_date%2C+close_date%2C+billing_method&limit=2&page_token=BAh7BjoLb2Zmc2V0aQc%3D--b1ea3eba20c8acefbcdfc7868debd1e0ee630c64&status=Open"
},
"records":91
}
}
I built the following schema within my c# code:
public class MatterList
{
public List<Matter> matters { get; set; }
public Meta meta { get; set; }
}
public class Meta
{
public Paging paging { get; set; }
public int records { get; set; }
}
public class Paging
{
public string previous { get; set; }
public string next { get; set; }
}
[DeserializeAs(Name = "data")]
public class Matter
{
public int id { get; set; }
public Client client { get; set; }
public string display_number { get; set; }
public string description { get; set; }
public PracticeArea practice_area { get; set; }
public string status { get; set; }
public DateTime open_date { get; set; }
public DateTime close_date { get; set; }
public string billing_method { get; set; }
public string type = "matter";
}
public class PracticeArea
{
public int id { get; set; }
public string name { get; set; }
}
public class Client
{
public int id { get; set; }
public string name { get; set; }
}
When I run the RestSharp deserialize method I am sending the result to an object of type MatterList using the following line of code
MatterList matterList = jsonHandler.Deserialize<MatterList>(response);
I have so far attempted to deserialize without the Meta or Paging POCO classes with the accompanying change to the MatterList class (taking out the Meta property).
I have tried with and without the [DeserializeAs(Name="data")] directive.
I have tried to set the RootElement of the json response prior to deserialization.
I have tried to shorthand the deserialization by combining it with the Execute request code
IRestResponse<MatterList> matterList = client.Execute<MatterList>(request);
I have created a container class called MatterContainer which I placed between MatterList and Matter classes in the schema:
public class MatterList
{
public List<MatterContainer> matters { get; set; }
}
public class MatterContainer
{
public Matter matter { get; set; }
}
public class Matter
{
public int id { get; set; }
public Client client { get; set; }
public string display_number { get; set; }
public string description { get; set; }
public PracticeArea practice_area { get; set; }
public string status { get; set; }
public DateTime open_date { get; set; }
public DateTime close_date { get; set; }
public string billing_method { get; set; }
public string type = "matter";
}
I know I am getting the json response back from the server correctly so my request is proper and MatterList is not null after deserialization. The problem is that I cannot get the deserialization to actually populate the List matters within the MatterList class.
I have been looking at this off and on for two days and cannot get past this hurdle. If anyone sees what I did wrong I would greatly appreciate the insight, I am at a point where I cannot progress further with my application.
Thanks!
I think your [DeserializeAs(Name = "data")] attribute is in the wrong place. Try putting it in the root class instead:
public class MatterList
{
[DeserializeAs(Name = "data")]
public List<Matter> matters { get; set; }
public Meta meta { get; set; }
}
alternatively, try renameing that property to data

Converting JSON to Object fails - Cannot deserialize the current JSON object into System.Collections.Generic.List

I'm using the API of www.textlocal.in, which returns a JSON formatted object.
JSON
{
"warnings":[
{
"message":"Number is in DND",
"numbers":"917000000000"
}
],
"balance":900,
"batch_id":311110011,
"cost":1,
"num_messages":1,
"message":{
"num_parts":1,
"sender":"TXTLCL",
"content":"Test1"
},
"receipt_url":"",
"custom":"",
"inDND":[
"917000000000"
],
"messages":[
{
"id":"1350123781",
"recipient":918819437284
}
],
"status":"success"
}
My code with which I'm trying to parse the JSON:
private void button1_Click(object sender, EventArgs e)
{
var a = JsonConvert.DeserializeObject<List<jsonToObj[]>>(richTextBox1.Text);
}
public class jsonToObj
{
public warnings[] warnings { get; set; }
public int balance { get; set; }
public int batch_id { get; set; }
public int cost { get; set; }
public int num_messages { get; set; }
public message message { get; set; }
public string receipt_url { get; set; }
public string custom { get; set; }
public messages[] messages { get; set; }
public string status { get; set; }
}
public class warnings
{
public string message { get; set; }
public string numbers { get; set; }
}
public class messages
{
public string id { get; set; }
public int recipient { get; set; }
}
public class message
{
public int num_part { get; set; }
public string sender { get; set; }
public string content { get; set; }
}
I'm getting an exception with the following message:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the
current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[WindowsFormsApp1.Form2+jsonToObj[]]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) 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. Path 'warnings', line 1, position
12.'
First of all you have to figure out what your API returns.
Right now you're trying to parse a List of jsonToObj Arrays (List<jsonToObj[]>). You have to decide whether to use a jsonToObj[] or List<jsonToObj> or a simple jsonToObj which your API provides now:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
But this then throws:
JSON integer 918819437284 is too large or small for an Int32. Path 'messages[0].recipient', line 25, position 33."
So make sure you use a Long for that.
public class messages
{
public string id { get; set; }
public long recipient { get; set; }
}
Furthermore you can add inDND to your jsonToObj class if you need the info:
public class jsonToObj
{
...
public string[] inDND { get; set; }
...
}
Based on string you class structure should be like this :
public class Warning
{
public string message { get; set; }
public string numbers { get; set; }
}
public class Message
{
public int num_parts { get; set; }
public string sender { get; set; }
public string content { get; set; }
}
public class Message2
{
public string id { get; set; }
public long recipient { get; set; }
}
public class RootObject
{
public List<Warning> warnings { get; set; }
public int balance { get; set; }
public int batch_id { get; set; }
public int cost { get; set; }
public int num_messages { get; set; }
public Message message { get; set; }
public string receipt_url { get; set; }
public string custom { get; set; }
public List<string> inDND { get; set; }
public List<Message2> messages { get; set; }
public string status { get; set; }
}
It looks like your class structure is not proper, Make use of visual studio and generate C# class from json string and then using that generated class try to deserialize class.
Read : Visual Studio Generate Class From JSON or XML
I simulated your problem and made the following changes that worked:
Change the method that deserializes to this:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
The result of the JSON you receive is not a List, so it will not work to deserialize to List<>.
The recipient property of the messages class receives values larger than an integer, so it must be transformed into a long like this:
public long recipient { get; set; }
These changes solve your problem.
Looks like this is a very old post, still thought of answering.
First of all, your Json data is singular which means, either
var a = JsonConvert.DeserializeObject<List<jsonToObj[]>>(richTextBox1.Text);
or
var a = JsonConvert.DeserializeObject<List<jsonToObj>>(richTextBox1.Text);
may not work for you.
You can either try:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
or
enclose the data with [ and ], which would do the trick.
make sure your parsing single object vs list of objects.

How to bind multilevel json data to a repeater in asp.net or converting json data to data table

I want to bind the Json data to the repeater I know only one process that is converting the Json data to data table and then binding data but here I am receiving multilevel json data i do't know how to convert them to data table
input json data:
{"apiAvailableBuses":
[{"droppingPoints":null,"availableSeats":40,"partialCancellationAllowed":false,"arrivalTime":"01:00 AM","cancellationPolicy":"[{\"cutoffTime\":\"1\",\"refundInPercentage\":\"10\"},{\"cutoffTime\":\"2\",\"refundInPercentage\":\"50\"},{\"cutoffTime\":\"4\",\"refundInPercentage\":\"90\"}]","boardingPoints":[{"time":"07:40PM","location":"K.P.H.B,Beside R.S Brothers","id":"2238"}],"operatorName":"Apple I Bus","departureTime":"8:00 PM","mTicketAllowed":false,"idProofRequired":false,"serviceId":"6686","fare":"1000","busType":"Hi-Tech A/c","routeScheduleId":"6686","commPCT":9.0,"operatorId":203,"inventoryType":0},
{
"droppingPoints":null,"availableSeats":41,"partialCancellationAllowed":false,"arrivalTime":"06:00 AM","cancellationPolicy":"[{\"cutoffTime\":\"1\",\"refundInPercentage\":\"10\"},{\"cutoffTime\":\"2\",\"refundInPercentage\":\"50\"},{\"cutoffTime\":\"4\",\"refundInPercentage\":\"90\"}]","boardingPoints":[{"time":"08:00PM","location":"Punjagutta,","id":"2241"}],"operatorName":"Royalcoach Travels","departureTime":"8:00 PM","mTicketAllowed":false,"idProofRequired":false,"serviceId":"6736","fare":"800","busType":"VOLVO","routeScheduleId":"6736","commPCT":9.0,"operatorId":243,"inventoryType":0}
I am trying to convert it to data table by
public void getavailablebuses()
{
string url = string.Format(HttpContext.Current.Server.MapPath("files/getavailablebuses.json"));
using (WebClient client = new WebClient())
{
string json = client.DownloadString(url);
var result = JsonConvert.DeserializeObject<RootObject>(json);
string mm = JObject.Parse(json).SelectToken("apiAvailableBuses").ToString();
// var boardingpoint = JObject.Parse(mm).SelectToken("boardingPoints").ToString();
var Availablebuses = JObject.Parse(json).SelectToken("apiAvailableBuses").ToString();
DataTable dt = (DataTable)JsonConvert.DeserializeObject(Availablebuses, (typeof(DataTable)));
}
public class apiresult
{
public string message { get; set; }
public string success { get; set; }
}
public class RootObject
{
public apiresult apiStatus;
public List<apiAvailableBuses> apiAvailableBuses{ get; set; }
// public string apiAvailableBuses { get; set; }
}
public class apiAvailableBuses
{
public string serviceId { get; set; }
public string fare { get; set; }
public string busType { get; set; }
public string departureTime { get; set; }
public string operatorName { get; set; }
public string cancellationPolicy { get; set; }
public List<boardingpoints> boardingpoints { get; set; }
public string droppingPoints { get; set; }
public string inventoryType { get; set; }
public string routeScheduleId { get; set; }
public int availableSeats { get; set; }
public string arrivalTime { get; set; }
public Boolean idProofRequired { get; set; }
public Boolean partialCancellationAllowed { get; set; }
public int operatorId { get; set; }
public double commPCT { get; set; }
public string mTicketAllowed { get; set; }
}
public class boardingpoints
{
public string location { get; set; }
public string id { get; set; }
public string time { get; set; }
}
public class cancellationPolicy
{
public string cutoffTime { get; set; }
public string refundInPercentage { get; set; }
}
Here in the data table I am unable to get the boarding points, dropping points and cancellation policy
if I load cancellation policy as list or JObject I am getting error
so here I am loading cancellation policy as string.
but I am unable to load boarding points and dropping points.
Please help with this I am scratching my head from two days. Thanks in advance
"I know only one method to bind data to a repeater i.e data table." So this is a perfect opportunity to learn other ways, wouldn't you say?
Why don't you work with the result of JsonConvert.DeserializeObject<RootObject>(json);? This is a RootObject that has a property called apiAvailableBuses which seems to be exactly what you need to bind to your repeater, no?
By the way, a bit of code review:
apiresult and apiAvailableBuses violate Microsoft's rules WRT class names: those should be in PascalCase. Same for the properties of apiresult, e.g. message and success. Same for the properties of apiAvailableBuses.
RootObject has a public field: apiStatus. That probably needs to be a a property with a getter/setter.
Moreover, apiAvailableBuses is plural, which is incorrect, since the data therein is of only one bus. Same for boardingpoints: the class contains data for a single point, not multiple.
Be consistent: if you use string, then also use bool and not Boolean.

Setting up a class to contain a list of objects

I am setting a class in C# to hold a response that I will be receiving from a web service call. I'm using RestSharp to handle the calling / parsing of the JSON data.
The web service documentation describes the response as:
OUTPUT: JSON object similar to example below.
{
"response":"[success] or [failed]",
"messages":"Process succeeded.",
"logonkey":"[logon key]",
"tokenkey":"[security token]",
"reccount":"1",
"filelist":
{
"fileid":"12345",
"status":"N",
"filename":"data.tar",
"fulfilled":"2012-06-15"
}
}
My question is how can I define the filelist array element in my class?
I was thinking something like this:
public class Files
{
public string Response { get; set; }
public string Messages { get; set; }
public string LogonKey { get; set; }
public string TokenKey { get; set; }
public int RecordCount { get; set; }
public List<FileList>
}
public class FileList
{
public string FileID { get; set; }
public string Status { get; set; }
public string Filename { get; set; }
public DateTime Fulfilled { get; set; }
}
However, I'm having a problem with the "public List" statement.
Any suggestions on the best way to handle this scenario would be appreciated.
Also you forgot to give it a name, for example try this
public List<FileList> MyFavouriteList {get;set;}.
A proprety is declared like this "access modifier", "Type", "identifier(or name)", "getter and setter".
The filelist in JSON sample doesn't look like list of objects. Instead it is a single object.
You could try,
public class Files
{
public string Response { get; set; }
public string Messages { get; set; }
public string LogonKey { get; set; }
public string TokenKey { get; set; }
public int RecordCount { get; set; }
public FileList File {get; set; }
}
If you are sure the filelist in JSON is really list of object, you could try,
public List<FileList> Files = new List<FileList>();

Categories

Resources