Deserialize Json String to C# object - c#

I'm trying out the Philips Hue lights api for the first time and I have a few questions on how to deserialize the json string to a C# object. I'm trying this out for the Xamarin.iOS app I'm working on.
Here's my method that would fetch the light data from around me:
private string getLights()
{
var url = APIURL + APIKey + LightsEndPoint ;
var request = WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
using (var response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.Out.WriteLine(
"Error fetching data. Server returned status code: {0}",
response.StatusCode);
using (var reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if(string.IsNullOrWhiteSpace(content))
{
Console.WriteLine("Response contained empty body...");
}
else
{
Console.WriteLine("Response Body: \r\n {0}", content);
var items = JsonConvert.DeserializeObject <Light> (content);
}
return content;
}
}
}
Where Light is:
public class Light
{
public Light()
{ }
public string LightName { get; set;}
[JsonProperty("state")]
public string IsOn { get; set; }
[JsonProperty("sat")]
public int Saturation { get; set; }
[JsonProperty("bri")]
public int Brightness {get;set;}
[JsonProperty("hue")]
public int Hue { get; set; }
}
The problem I'm having now is my items object is always empty, null values even though I'm properly getting content json string.
My json string looks like this:
{
"1":{
"state":{
"on":true,
"bri":254,
"hue":20000,
"sat":100,
"effect":"none",
"xy":[
0.4146,
0.4155
],
"ct":299,
"alert":"none",
"colormode":"hs",
"reachable":true
},
"type":"Extended color light",
"name":"Hue color lamp 1",
"modelid":"LCT007",
"manufacturername":"Philips",
"uniqueid":"00:17:88:01:10:26:3f:12-0b",
"swversion":"5.38.1.14919"
},
"2":{
"state":{
"on":false,
"bri":254,
"hue":50000,
"sat":254,
"effect":"none",
"xy":[
0.2468,
0.0843
],
"ct":153,
"alert":"none",
"colormode":"hs",
"reachable":true
},
"type":"Extended color light",
"name":"Hue color lamp 2",
"modelid":"LCT007",
"manufacturername":"Philips",
"uniqueid":"00:17:88:01:10:5d:fd:f6-0b",
"swversion":"5.38.1.14919"
},
"3":{
"state":{
"on":true,
"bri":254,
"hue":10000,
"sat":254,
"effect":"none",
"xy":[
0.5711,
0.3986
],
"ct":500,
"alert":"none",
"colormode":"hs",
"reachable":true
},
"type":"Extended color light",
"name":"Hue color lamp 3",
"modelid":"LCT007",
"manufacturername":"Philips",
"uniqueid":"00:17:88:01:10:26:3d:17-0b",
"swversion":"5.38.1.14919"
}
}
The problem I'm having is light is indicated by a numerical value and I'm not sure how to split the json string to populate my c# object.
Basically, I'm having issues converting the json string to c# object for api stream for Xamarin.iOS app.

Your model should look like this
public class Light
{
public Light()
{
}
[JsonProperty("name")]
public string LightName { get; set;}
[JsonProperty("state")]
public State State { get; set; }
}
public class State
{
public State()
{
}
[JsonProperty("on")]
public bool IsOn { get; set; }
[JsonProperty("sat")]
public int Saturation { get; set; }
[JsonProperty("bri")]
public int Brightness {get;set;}
[JsonProperty("hue")]
public int Hue { get; set; }
}
And deserialization call should look like this
JsonConvert.DeserializeObject<Dictionary<string, Light>>(content);
Where the key of the dictionary is the numbers and value is the light model you want to get.

I generated a class with json2csharp:
public class State
{
public bool on { get; set; }
public int bri { get; set; }
public int hue { get; set; }
public int sat { get; set; }
public string effect { get; set; }
public List<double> xy { get; set; }
public int ct { get; set; }
public string alert { get; set; }
public string colormode { get; set; }
public bool reachable { get; set; }
}
public class RootObject
{
public State state { get; set; }
public string type { get; set; }
public string name { get; set; }
public string modelid { get; set; }
public string manufacturername { get; set; }
public string uniqueid { get; set; }
public string swversion { get; set; }
}
then I called this code:
var a = JsonConvert.DeserializeObject<Dictionary<string, RootObject>>(json);
and the result was this:

As mentioned, your model structure does not match that of the json's. You need to properly nest the properties accordingly. I threw together an example, though certain data types I was unsure of I simply used a string(Which should be fine).
Light.cs
public class Light
{
public string LightName { get; set; }
[JsonProperty("state")]
public State LightState { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("modelid")]
public string ModelId { get; set; }
[JsonProperty("manufacturername")]
public string Manufacturer { get; set; }
[JsonProperty("uniqueid")]
public string UniqueId { get; set; }
[JsonProperty("swversion")]
public string SwVersion { get; set; }
}
State.cs
public class State
{
[JsonProperty("on")]
public bool IsOn { get; set; }
[JsonProperty("bri")]
public int Brightness { get; set; }
[JsonProperty("hue")]
public int Hue { get; set; }
[JsonProperty("sat")]
public int Saturation { get; set; }
[JsonProperty("effect")]
public string Effect { get; set; } // Just making it a string for now
[JsonProperty("xy")]
public double[] XY { get; set; }
[JsonProperty("ct")]
public int CT { get; set; }
[JsonProperty("alert")]
public string Alert { get; set; } // Just making another string for now
[JsonProperty("colormode")]
public string ColorMode { get; set; } // Hey, it's another string for now
[JsonProperty("reachable")]
public bool Reachable { get; set; }
}
Then to deserialize:
var items = JsonConvert.DeserializeObject<Dictionary<string, Light>> (content);

Related

How to read sections of JSON document?

I have a JSON document and I want to access the details of the STATUS SECTION but it keeps returning null.
JSON Data is as shown:
{
"results":[
{
"messageId":"15712480583306574",
"to":"",
"from":"TestServer",
"sentAt":"2019-10-16T17:47:38.368+0000",
"doneAt":"2019-10-16T17:47:38.370+0000",
"smsCount":1,
"mccMnc":"null",
"price":{
"pricePerMessage":0.0,
"currency":"USD"
},
"status":{
"groupId":5,
"groupName":"REJECTED",
"id":8,
"name":"REJECTED_PREFIX_MISSING",
"description":"Number prefix missing"
},
"error":{
"groupId":0,
"groupName":"OK",
"id":0,
"name":"NO_ERROR",
"description":"No Error",
"permanent":false
}
}
]
}
C# Code is:
string JsonData = response.Content.ToString();
dynamic results = JsonConvert.DeserializeObject<dynamic>(JsonData);
var statuses = results.status;
foreach(var stat in statuses) {
string groupname = stat.groupName.Value;
string name = stat.name.Value;
string description = stat.description.Value;
}
It keeps returning null, How can I access these members? I am using Newtonsoft.
If you want to access the status object property you need to rewrite your whole code.
string JsonData = response.Content.ToString();
var input = JObject.Parse(str);
var results = input["results"].Children();
var status = results.First()["status"];
string groupname = status["groupName"].ToString();
string name = status["name"].ToString();
string description = status["description"].ToString();
Console.WriteLine(groupname);
Console.WriteLine(name);
Console.WriteLine(description);
The result in Console
REJECTED
REJECTED_PREFIX_MISSING
Number prefix missing
But I would rather use concrete class. You need to create multiple classes. Here is good example.
public class Envelope
{
public List<Item> Results { get; set; }
}
public class Item
{
public Status Status { get; set; }
}
public class Status
{
public int GroupId { get; set; }
public string GroupName { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
After that the usage is much simpler.
string JsonData = response.Content.ToString();
MyEnvelope envelope = JsonConvert.DeserializeObject<MyEnvelope>(JsonData);
var status = envelope.results[0].status;
Console.WriteLine(status.GroupName);
Console.WriteLine(status.Name);
Console.WriteLine(status.Description);
Finest Option: Create A model for the JSON.
public class Price
{
public double pricePerMessage { get; set; }
public string currency { get; set; }
}
public class Status
{
public int groupId { get; set; }
public string groupName { get; set; }
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
public class Error
{
public int groupId { get; set; }
public string groupName { get; set; }
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public bool permanent { get; set; }
}
public class Result
{
public string messageId { get; set; }
public string to { get; set; }
public string from { get; set; }
public DateTime sentAt { get; set; }
public DateTime doneAt { get; set; }
public int smsCount { get; set; }
public string mccMnc { get; set; }
public Price price { get; set; }
public Status status { get; set; }
public Error error { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
Then do RootObject results = JsonConvert.DeserializeObject<RootObject>(JsonData);
Fair Option: Get the exact JToken you want.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string jsonData = "{\"results\":[{\"messageId\":\"15712480583306574\",\"to\":\"\",\"from\":\"TestServer\",\"sentAt\":\"2019-10-16T17:47:38.368+0000\",\"doneAt\":\"2019-10-16T17:47:38.370+0000\",\"smsCount\":1,\"mccMnc\":\"null\",\"price\":{\"pricePerMessage\":0.0,\"currency\":\"USD\"},\"status\":{\"groupId\":5,\"groupName\":\"REJECTED\",\"id\":8,\"name\":\"REJECTED_PREFIX_MISSING\",\"description\":\"Number prefix missing\"},\"error\":{\"groupId\":0,\"groupName\":\"OK\",\"id\":0,\"name\":\"NO_ERROR\",\"description\":\"No Error\",\"permanent\":false}}]}";
JObject jObject = JObject.Parse(jsonData);
Console.WriteLine(jObject.SelectToken("results[0].status"));
}
}

Incorrect JSON Output Using ASP.NET

Please excuse this question as a sign of frustration. While I understand that cause of the issue is the converting of data into different types, I can't put my finger on what's causing the result of this web service get method to be output incorrectly, that is containing backslashes.
The code below sums up the functionality of my method. I've tried different suggestions I found on these forums, some of which were in reply to similar questions I asked myself.
Data Model
public class WeatherResponse
{
public class Coord
{
public double lon { get; set; }
public double lat { 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; }
}
public class Main
{
public double temp { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public int temp_min { get; set; }
public int temp_max { get; set; }
}
public class Wind
{
public double speed { get; set; }
public int deg { get; set; }
}
public class Clouds
{
public int all { get; set; }
}
public class Sys
{
public int type { get; set; }
public int id { get; set; }
public double message { get; set; }
public string country { get; set; }
public int sunrise { get; set; }
public int sunset { get; set; }
}
public class RootObject
{
public Coord coord { get; set; }
public List<WeatherResponse> weather { get; set; }
public string #base { get; set; }
public Main main { get; set; }
public int visibility { get; set; }
public Wind wind { get; set; }
public Clouds clouds { 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; }
}
}
Controller
[HttpGet]
public string Get(string city, string country)
{
string apiKey = "KEY";
HttpWebRequest apiRequest = WebRequest.Create("http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + country + " &appid=" + apiKey + "&units=metric") as HttpWebRequest;
string apiResponse = "";
using (HttpWebResponse response = apiRequest.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
apiResponse = reader.ReadToEnd();
}
Response.ContentType = "application/json";
return apiResponse;
}
Result
"{\"coord\":{\"lon\":-0.13,\"lat\":51.51},\"weather\":[{\"id\":521,\"main\":\"Rain\",\"description\":\"shower
rain\",\"icon\":\"09d\"}],\"base\":\"stations\",\"main\":{\"temp\":2.62,\"pressure\":991,\"humidity\":69,\"temp_min\":1,\"temp_max\":4},\"visibility\":10000,\"wind\":{\"speed\":5.1,\"deg\":90},\"clouds\":{\"all\":75},\"dt\":1548939000,\"sys\":{\"type\":1,\"id\":1414,\"message\":0.0037,\"country\":\"GB\",\"sunrise\":1548920401,\"sunset\":1548953318},\"id\":2643743,\"name\":\"London\",\"cod\":200}"
I need the code to simply retrieve weather data using the city and country received and correctly output it as JSON.
Here's the solution to the problem, as kindly posted by Joroen Mostert.
You should be able to use Content for this (when you change the return
type of your method to IActionResult): return Content(apiResponse,
"application/json") should not further escape.

Deserializing a nested JSON string, cannot access properties

I am having issues deserializing a nested JSON array from the Genius lyric website API. I formulated the object using http://json2csharp.com. When I deserialize the object, I am unable to access the properties inside of the class, which wasn't entirely unexpected, I am just not sure how to properly design an actual solution to the problem. The JSON object conversions work fine when they are not nested.
What would be the best way to go about handling this?
Here is the conversion code:
string test = await G.SearchGeniusASync(textBox1.Text);
var data = JsonConvert.DeserializeObject<GeniusApiObject>(test);
Here is my class:
class GeniusApiObject
{
public class Meta
{
public int status { get; set; }
}
public class Stats
{
public bool hot { get; set; }
public int unreviewed_annotations { get; set; }
public int concurrents { get; set; }
public int pageviews { get; set; }
}
public class PrimaryArtist
{
public string api_path { get; set; }
public string header_image_url { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public bool is_meme_verified { get; set; }
public bool is_verified { get; set; }
public string name { get; set; }
public string url { get; set; }
public int iq { get; set; }
}
public class Result
{
public int annotation_count { get; set; }
public string api_path { get; set; }
public string full_title { get; set; }
public string header_image_thumbnail_url { get; set; }
public string header_image_url { get; set; }
public int id { get; set; }
public int lyrics_owner_id { get; set; }
public string lyrics_state { get; set; }
public string path { get; set; }
public int? pyongs_count { get; set; }
public string song_art_image_thumbnail_url { get; set; }
public Stats stats { get; set; }
public string title { get; set; }
public string title_with_featured { get; set; }
public string url { get; set; }
public PrimaryArtist primary_artist { get; set; }
}
public class Hit
{
public List<object> highlights { get; set; }
public string index { get; set; }
public string type { get; set; }
public Result result { get; set; }
}
public class Response
{
public List<Hit> hits { get; set; }
}
public class RootObject
{
public Meta meta { get; set; }
public Response response { get; set; }
}
}
This is the source for the SearchGeniusASync method in case it is helpful:
public async Task<string>SearchGeniusASync(string searchParameter)
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", clientAccessToken);
var result = await httpClient.GetAsync(new Uri("https://api.genius.com/search?q=" + searchParameter), HttpCompletionOption.ResponseContentRead);
var data = await result.Content.ReadAsStringAsync();
return data;
}
This is the scope I am given access to:
https://i.imgur.com/9mZMvfp.png
Here's a sample JSON request in plaintext:
https://pastebin.com/iA8dQafW
GeniusApiObject is not needed in the code, but I'll leave it in just because it helps organize things (may be that something else also has a RootObject from the auto-generator).
The problem is that you are trying to deserialize to what is just an empty class, the class itself has no properties, so you can't deserialize to it. You need to deserialize to the GeniusApiObject.RootObject.
var data = JsonConvert.DeserializeObject<GeniusApiObject.RootObject>(test);
Will deserialize to the .RootObject subclass. This is verified working:
Where I'm using File.ReadAllText("test.json") to load the example API data provided.
Here is a .NET Fiddle showing it working (without the root object and only one song in the response). Thanks to #maccttura.

Deserializing object with dynamic property won't work

I'm having troubles with deserializing an object with a dynamic field, which will hold different api responses.
This is how it looks like:
public class ServiceCallResult
{
private dynamic _dataObject;
private Type _dataType;
public Type DataType
{
get
{
return _dataType;
}
set
{
_dataType = value;
}
}
public dynamic DataObject
{
get
{
return _dataObject;
}
set
{
_dataObject = value;
}
}
public string ErrorMessage { get; set; }
public bool Success { get; set; }
public ServiceCallResult()
{
}
public ServiceCallResult(Type type, dynamic obj)
{
DataType = type;
DataObject = obj;
Success = true;
}
}
And it could hold an object like this:
public class ApiPractitioner
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CompanyName { get; set; }
public int CVR { get; set; }
public string Address { get; set; }
public short ZipCode { get; set; }
public string City { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Description { get; set; }
public byte[] ProfileImage{ get; set; }
//[JsonIgnore]
//public List<ApiPractice> Practices { get; set; }
//[JsonIgnore]
//public List<ApiClient> Clients { get; set; }
}
But when deserializing with this code:
var req = new RestRequest("practitioner/createpractitioner", Method.POST);
req.RequestFormat = DataFormat.Json;
req.AddBody(prac);
var response = _client.Execute<ServiceCallResult>(req);
ServiceCallResult td = new JsonDeserializer().Deserialize<ServiceCallResult>(response);
It ends up with a "MissingMethodException" in mscorlib.dll, additional information is "An abstract class can't be created".
The response object has the json content but there's and exception like the one when I use the JsonDeserializer and I can't figure out what's going on, I've searched for hours on Google and tried different suggestions with no luck.
Anyone tried the same with a dynamic property?
I'm using RestSharp for the json handling.
Best regards
Benjamin
After a little enlightment from Michael I've changed my ServiceCallResult to this:
public class ServiceCallResult<T> where T : BaseApiResponse
{
public T DataObject { get; set; }
public string ErrorMessage { get; set; }
public bool Success { get; set; }
public ServiceCallResult()
{
}
public ServiceCallResult(T obj)
{
DataObject = obj;
Success = true;
}
}
And all my api responses inherits from BaseApiResponse.

error in working with json in WUP C# app

I have a problem in working with JSON. I have a published JSON on the web. The content of my JSON is this now:
"[{\"Column\":4,\"GroupId\":2020,\"GroupTitle\":\"نرم افزار کاربردی\",\"Average\":0.0,\"Cost\":1000,\"IconSquare\":\"~\\\\Files\\\\82\\\\Programs\\\\ProPlayer_V0.0.1.0\\\\839fcb30-3dfc-4b6f-a826-57601dad5047.jpg\",\"IconWide\":\"~\\\\Files\\\\82\\\\Programs\\\\ProPlayer_V0.0.1.0\\\\26777d6a-025d-40a8-b83a-12fcb1f97ca4.jpg\",\"Id\":3,\"NameEnglish\":\"ProPlayer\",\"NamePersian\":\"پروپلیر\",\"Size\":2.75,\"Version\":\"0.0.1.0\",\"VersionWindowsPhone\":\"ویندوزفون 8.1 و بالاتر\",\"Score\":0.0,\"Availables\":\"ویدئو ها\\r\\nموزیک ها\",\"Description\":\"برنامه خوبیه اما در حد تست \",\"Develeoper\":\" \",\"DTPublication\":\"2015-08-23T17:20:31.46\",\"Star1\":0,\"Star2\":0,\"Star3\":0,\"Star4\":0,\"Star5\":0,\"ProgramPath\":\"~\\\\Files\\\\82\\\\Programs\\\\ProPlayer_V0.0.1.0\\\\ProPlayer_V0.0.1.0.appxbundle\"}]"
I used Json.Net from NewtonSoft. Here is my class to convert JSON to this class type :
public class AppOrGame
{
public int Column { get; set; }
public int GroupId { get; set; }
public string GroupTitle { get; set; }
public float Average { get; set; }
public int Cost { get; set; }
public Uri IconSquare { get; set; }
public Uri IconWide { get; set; }
public int Id { get; set; }
public string NameEnglish { get; set; }
public string NamePersian { get; set; }
public float Size { get; set; }
public string Version { get; set; }
public string VersionWindowsPhone { get; set; }
public float Score { get; set; }
public string Availables { get; set; }
public string Description { get; set; }
public string Develeoper { get; set; }
public DateTime DTPublication { get; set; }
public int Star1 { get; set; }
public int Star2 { get; set; }
public int Star3 { get; set; }
public int Star4 { get; set; }
public int Star5 { get; set; }
public Uri ProgramPath { get; set; }
}
.
And here is my code to download a JSON string and then convert :
public async Task<string> DownloadStringsFromWeb(string uri)
{
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
string res = "";
webrequest.Method = "GET";
using (var webresponse = await webrequest.GetResponseAsync())
using (StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream()))
{
res = loResponseStream.ReadToEnd();
}
try
{
var a = JsonConvert.DeserializeObject <List<MainPage.AppOrGame>> (res);
}
catch (Exception ex)
{
}
return res;
}
The DownloadStringsFromWeb is not the final function so I put the JSON converter in it too but I will separate them from each other. When I debug my code I get an exception on JsonConvert
{"Error converting value {Exact Json value I provided above}
to type 'System.Collections.Generic.List`1[Universal4Khune.MainPage+AppOrGame]'. Path '', line 1, position 818."}
The " (double quote) isn't a symbol to be escaped in JSON context. Fix of the issue is depends on how do you produce the JSON? If it is in the file, for example, just remove backslashes. To be more specific, I should know the nature of your JSON.

Categories

Resources