Parsing Json in C# with JSON.NET - c#

I am developing an application in c# that gets the players backpack value on a game called TF2 using Backpack.tf's api.
At the moment the code is:
(MAIN CLASS)
JsonConvert.DeserializeObject<Json1>(json);
(END OF MAIN CLASS)
public class Json1 {
public static List<Json2> response { get; set; }
}
public class Json2
{
public static int success { get; set; }
public static int current_time { get; set; }
public static IEnumerable<Json4> players { get; set; }
}
public class Json4 {
public static int steamid { get; set; }
public static int success { get; set; }
public static double backpack_value { get; set; }
public static string name { get; set; }
}
I've cut out all the other crap out of the main class etc but suffice it to say that yes i've got the json code into the json string ready for deserializing (Tested it with Console.Writeline)
The problem is. Whenever I use things like Json4.name (when writing to console)
it always returns 0.
Sorry if I've made a stupid mistake but I think I've tried things like removing static, changing variable types etc but I still can't get it to work. Please note this is my first attemopt at deserializing Json code and I wrote the classes at bottom myself because some reason http://json2csharp.com/ didn't work. Heres the Json I am trying to deserialize:
{
"response":{
"success":1,
"current_time":1365261392,
"players":{
"0":{
"steamid":"76561198045802942",
"success":1,
"backpack_value":12893.93,
"backpack_update":1365261284,
"name":"Brad Pitt",
"stats_tf_reputation":2257,
"stats_tf_supporter":1,
"notifications":0
},
"1":{
"steamid":"76561197960435530",
"success":1,
"backpack_value":4544.56,
"backpack_update":1365254794,
"name":"Robin",
"notifications":0
}
}
}
}
(formatting messed up a bit. Also please excuse some spelling mistakes :) )

You have several problems with your code:
a) All your fields are static. Remove static; you need them to be instance members.
b) The response property in Json1 should be just a single instance, not a list.
c) Players needs to be a dictionary (or custom type), not an IEnumerable, since it is not an array in the JSON.
d) StreamId has really big numbers that will not fit into an int; change this to long (or string).
public class Json1
{
public Json2 response { get; set; }
}
public class Json2
{
public int success { get; set; }
public int current_time { get; set; }
public IDictionary<int, Json4> players { get; set; }
}
public class Json4
{
public long steamid { get; set; }
public int success { get; set; }
public double backpack_value { get; set; }
public string name { get; set; }
}

Related

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.

When consuming a web service, how do I know the type of the data being returned via JSON?

I have no previous experience with JSON or using web services, however I'm trying to consume a web service that returns meteorological information.
Here's the documentation on the API that I'm trying to use.
This API gives me data serialized with JSON. I did some reading into JSON, and from what I understand, the best way to access this serialized data after I download it would be to de-serialize it into an object with matching properties and types. Did I get this part right? I don't understand however in this case how am I supposed to accurately know the types of the data returned via JSON.
In the API that I mentioned before I got this example of a response from the API in JSON:
{"coord":
{"lon":145.77,"lat":-16.92},
"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],
"base":"cmc stations",
"main":{"temp":293.25,"pressure":1019,"humidity":83,"temp_min":289.82,"temp_max":295.37},
"wind":{"speed":5.1,"deg":150},
"clouds":{"all":75},
"rain":{"3h":3},
"dt":1435658272,
"sys":{"type":1,"id":8166,"message":0.0166,"country":"AU","sunrise":1435610796,"sunset":1435650870},
"id":2172797,
"name":"Cairns",
"cod":200}
What I did was, on Visual Studio I used the "Paste Special" > "Paste as JSON classes" option, which created these classes for me:
public class Rootobject
{
public Coord coord { get; set; }
public Weather[] weather { get; set; }
public string _base { get; set; }
public Main main { get; set; }
public Wind wind { get; set; }
public Clouds clouds { get; set; }
public Rain rain { get; set; }
public int dt { get; set; }
public Sys sys { get; set; }
public int id { get; set; }
public string name { get; set; }
public int cod { get; set; }
}
public class Coord
{
public float lon { get; set; }
public float lat { get; set; }
}
public class Main
{
public float temp { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public float temp_min { get; set; }
public float temp_max { get; set; }
}
public class Wind
{
public float speed { get; set; }
public int deg { get; set; }
}
public class Clouds
{
public int all { get; set; }
}
public class Rain
{
public int _3h { get; set; }
}
public class Sys
{
public int type { get; set; }
public int id { get; set; }
public float message { get; set; }
public string country { get; set; }
public int sunrise { get; set; }
public int sunset { get; set; }
}
public class Weather
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
The problem is that when I request data using the HttpClient, when I try to de-serialize the response I get I few errors regarding mismatching data types, like for example, float data being assign to properties of the type int.
Here's a snippet of my code:
string json = await client.GetStringAsync("weather?q=London,uk&appid=010101010101010101101");
Rootobject currentWeather = new Rootobject();
currentWeather = JsonConvert.DeserializeObject<Rootobject>(json);
MessageBox.Show(currentWeather.name);
I understand that in this case I could change the types of the properties in my classes to match what is being returned by the API, however that doesn't feel right to me, mainly because seems like it could be a source of troubles and unpredictable behavior. Am I doing this right? Maybe I'm missing something in the API documentation, shouldn't they provide the type of the data being returned?
Correct : De-serialize it into an object with matching properties and types.
First check the API documentation for the types, and if that is not comprehensiive enough I would consider changing your types to match what you infer from the JSON.
A value of 289.9 is a float.
A value of 1435650870 can be stored an int.
A value of AU can be a string/enum.
Edit:
I checked the API documentation you linked to and don't see anywhere were it explicitly states the types of data returned.
Edit 2:
Answering your question more directly, "how am I supposed to accurately know the types of the data returned via JSON?" (thanks #CodeCaster), without finding that information in documentation I don't think you can.
But I feel you can get 99.999% close by just looking at historical data returned.
If it is satisfied for you to use dynamic you can try this snippet
string json = await client.GetStringAsync("weather?q=London,uk&appid=010101010101010101101");
dynamic currentWeather= JObject.Parse(json);
MessageBox.Show(currentWeather.name);
You will find more details in documentation

Web api skips all objects but first in List<T> when returning to client

I have a web api that returns a complex object that looks like this:
public class CanDeleteRumsaAttributeResponse
{
public CanDeleteRumsaAttributeResponse()
{
}
public CanDeleteRumsaAttributeResponse(int attributeId)
{
RumsaAttributeId = attributeId;
}
public int RumsaAttributeId { get; set; }
public bool AttributeFound { get; set; }
public List<RumsaRoom> AffectedRumsaRooms { get; set; } = new List<RumsaRoom>();
public List<RumsaAttribute> AffectedLinkedRumsaAttributes { get; set; } = new List<RumsaAttribute>();
[JsonIgnore]
public bool CanDelete
{
get
{
return AffectedRumsaRooms.Count == 0&&AttributeFound&&AffectedLinkedRumsaAttributes.Count==0;
}
}
}
When I debug it I can see that the controller return that object and that the list AffectedLinkedRumsaAttributes has several objects in the list
When the client receives the list all but the first object are null.
I've tried returning the object as Ok(CanDeleteRumsaAttributeResponse) and I've tried serializing it like this:
RoomAttributesUtils utils = new RoomAttributesUtils(db);
string json = JsonConvert.SerializeObject(utils.GetCanDeleteColor(id));
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(json, Encoding.UTF8, "application/json");
return response;
In the second case I can search the json string and find the missing data.
So its being serialized in the second case.
I've checked fiddler to see what is being sent and I can see that something is not right in the json-data.
The missing objects gets values like $ref: "4" and so on, but nothing else.
Here is the json-string I'm afraid I dont know how to format it properly for Stackoverflow, but I think that the information is there as well, but when I look at it using a viewer, its not and it sure doesnt deserialize to the correct objects.
The other list in the object can have any number of objects and they all return fine. Also, other endpoints are returning lists of the same type perfectly fine.
The three objects have unique values on the Code property and they are V30, V31 and V12 (if you want to identify them in the json string).
Any ideas?
Here is the json string
{"RumsaAttributeId":4797,"AttributeFound":true,"AffectedRumsaRooms":[{"$id":"1","RoomName":"STÄD","RoomNumber":"U12102-1150","Building":"U1","PartOfBuilding":"21","Plan":"02","Number":"1150","RoomDescriptions":[],"IsDeleted":false,"PMs":[],"IDNR":"175D_40","Exclude":false,"Department":"VN40 Lokalvård","Comments":"","Area":"23.19","HygeneClass":null,"CeilingHeight":"","UniqueRoomId":"d00e5325-7918-4d01-b273-813a770b46ca-010591d3","SolviegHasOpenedThis":true,"LastSynchedFromRevit":"1900-01-01T00:00:00","LastUpdatedFromRevit":"1900-01-01T00:00:00","Id":25772}],"AffectedLinkedRumsaAttributes":[{"$id":"2","AMACode":"KBC.3211","Malning":"56-03510","AvaliableColors":[{"$id":"3","AvaliableMaterials":[{"$ref":"2"},{"$id":"4","AMACode":"MBE.221","Malning":"-","AvaliableColors":[{"$ref":"3"}],"RoomDescriptions":[],"Code":"V30","ShortDescription":"Kakel, vattenavvisande beklädnad","LongDescription":"-","Comment":"-","PartOfRoom":null,"PartOfRoomId":960,"Id":1438},{"$id":"5","AMACode":"MBE.222","Malning":"-","AvaliableColors":[{"$ref":"3"}],"RoomDescriptions":[],"Code":"V31","ShortDescription":"Kakel, vattentät beklädnad","LongDescription":"-","Comment":"-","PartOfRoom":null,"PartOfRoomId":960,"Id":1439}],"RoomDescriptions":[],"Code":"V31_01","ShortDescription":"Kakel, vattentät beklädnad","LongDescription":"Marazzi SistemC Arch ME83, kulör Bianco(vit)200x200x5 mm. Fog Mapei Ultracolor Plus kulör 111 Silver Grey","Comment":"På 1 fondvägg","PartOfRoom":null,"PartOfRoomId":960,"Id":4797}],"RoomDescriptions":[],"Code":"V12","ShortDescription":"Gipsskivor, hygienklass 2","LongDescription":"Hög standard, hygienklass 2\n","Comment":"-","PartOfRoom":null,"PartOfRoomId":960,"Id":1425},{"$ref":"4"},{"$ref":"5"}]}
I had a similar situation in which I found that due to circular references, the serialization was not completed.
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogForeignKey { get; set; }
[ForeignKey("BlogForeignKey")]
public Blog Blog {get;set;}
}
I just deleted the child to parent relationship and included the foreingkey anotation to the entity set.
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[ForeignKey("BlogForeignKey")]
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogForeignKey { get; set; }
}
Also consider LoopReferenceHandling

Deserialize nested JSON object with unknow value

I'm coming today for a little problem where I'm stuck.
I'm making a c# xamarin app and this one receives messages (JSON) from my server.
The thing is, this message contains 2 fixes variables (String Descrption, Int StatusId).
However, a third value is put in this message. This value can be either an object or a range of object. It means that my class can be the two following possibilities:
Case 1 -> I got an object as Result
public class Result
{
public string name { get; set; }
}
public class RootObject
{
public string Description { get; set; }
public Result Results { get; set; }
public int StatusId { get; set; }
}
Case 2 -> I got a list of results as List<Result>
public class Result
{
public string name { get; set; }
}
public class RootObject
{
public string Description { get; set; }
public List<Result> Results { get; set; }
public int StatusId { get; set; }
}
Of course, it's all time a Result object which is get, however, it can be either alone or such as a list.
How can I deserialize this object JSON into the right class if this object can have two possibilities of unserialization?

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

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.

Categories

Resources