deserialize api response w/newtonsoft - c#

I need help deserializing a response. (I'm making a call to Data247 on a phone number, and the api returns the mobile phone carrier). The api call is working and I'm getting back a valid response that looks like this:
{
"response": {
"status": "OK",
"results": [
{
"phone": "11234567890",
"wless": "y",
"carrier_name": "Blue Licenses Holding, LLC",
"carrier_id": 6,
"sms_address": "1234567890#txt.att.net",
"mms_address": "1234567890#mms.att.net"
}
]
}
}
This is in a C#.NET winforms app. To test this, you'd have to have an access key from Data247. Everything is working through the api call. My problem is with this line:
Data247 data247 = JsonConvert.DeserializeObject<Data247>(response.Content);
...and so I don't think my class is structured correctly. ...or maybe I'm not deserializing correctly.
My code looks like this:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using RestSharp;
using Newtonsoft.Json;
namespace myTest
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void btnVerify_Click(object sender, EventArgs e)
{
try
{
string request = txtEndpoint.Text;
request += "?key=" + txtAccessKey.Text;
request += "&api=CU";
request += "&phone=" + txtPhone.Text;
var client = new RestClient(request);
var response = client.Execute(new RestRequest());
Data247 data247 = JsonConvert.DeserializeObject<Data247>(response.Content);
MessageBox.Show(response.Content);
Debug.Print(response.Content);
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
}
}
public class Data247
{
Response response { get; set; }
public class Response
{
public string status { get; set; }
Results results { get; set; }
public class Results
{
List<Phone> phones = new List<Phone>();
public Phone phone { get; set; }
public class Phone
{
public string phone { get; set; }
public string wless { get; set; }
public string carrier_name { get; set; }
public string carrier_id { get; set; }
public string sms_address { get; set; }
public string mms_address { get; set; }
}
}
}
}
}
}

Besides the recommended trick from #Hirasawa, I believe it's important to understand how all this works, so I would like to point out a couple of glitches in your code.
You don't need the Phone class.
If you look at the structure of the data, the phone number is only a property of the result item. Also, Results is an array, so let's update the code to fix those errors:
public class Data247
{
Response response { get; set; }
public class Response
{
public string status { get; set; }
public Results[] results { get; set; }
public class Results
{
public string phone { get; set; }
public string wless { get; set; }
public string carrier_name { get; set; }
public string carrier_id { get; set; }
public string sms_address { get; set; }
public string mms_address { get; set; }
}
}
}
Target properties must be public.
In order to correctly deserialize the response, the properties in your target classes must be public. Fixing those errors we get:
public class Data247
{
public Response response { get; set; }
public class Response
{
public string status { get; set; }
public Results[] results { get; set; }
public class Results
{
public string phone { get; set; }
public string wless { get; set; }
public string carrier_name { get; set; }
public string carrier_id { get; set; }
public string sms_address { get; set; }
public string mms_address { get; set; }
}
}
}
With the above changes, the code now works. Well, almost ;-). It turns out that we now have a nested class Results at the same level of a property named Results. This is not valid in C# and the compiler will let you know that with an error: "There is already a Results member declared.".
The fix is easy though, we just move the nested classes to the outer scope or we could rename the Response and Results classes to something like ResponseDTO and ResultDTO, but I find the former easier to do. So now our code is:
public class Data247
{
public Response response { get; set; }
}
public class Response
{
public string status { get; set; }
public Results[] results { get; set; }
}
public class Results
{
public string phone { get; set; }
public string wless { get; set; }
public string carrier_name { get; set; }
public string carrier_id { get; set; }
public string sms_address { get; set; }
public string mms_address { get; set; }
}
BONUS: Write idiomatic C# code.
If you want to write idiomatic code, you should use the recommended property names. This is a matter of style and the code as it is is working, but a C# developer will thank you if your code is properly written.
This is a brief summary of what I'll do:
Rename property names to UpperCamelCase format. Eg: mms_address should be MmsAddress.
Due to 1. we must also use attributes to map the actual property names in the json to the C# property name.
Below is the final code:
public class Data247
{
[JsonProperty("Response")]
public Response Response { get; set; }
}
public class Response
{
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("results")]
public Results[] Results { get; set; }
}
public class Results
{
[JsonProperty("Phone")]
public string Phone { get; set; }
[JsonProperty("wless")]
public string Wless { get; set; }
[JsonProperty("carrier_name")]
public string CarrierName { get; set; }
[JsonProperty("carrier_id")]
public string CarrierId { get; set; }
[JsonProperty("sms_address")]
public string SmsAddress { get; set; }
[JsonProperty("mms_address")]
public string MmsAddress { get; set; }
}
Hope this helps!

https://dailydotnettips.com/did-you-know-you-can-automatically-create-classes-from-json-or-xml-in-visual-studio/
And this is how you get the (mostly) correct class for any json structure.

Related

How to process a json response from an API in C#

I've read and reread articles online on how to do this, but it's probably something simple. I'm trying to learn how to process a json response from an API call. I have a simple method I call from Main()
public async void apiTestCall()
{
var httpCall = new HttpClient();
var uri = new Uri("https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=1000&page=2&api_key=DEMO_KEY");
var result = new DataModel();
var response = await httpCall.GetStringAsync(uri);
result = JsonSerializer.Deserialize<DataModel>(response);
I am expecting "result" to be a DataModel object with the data populated. Right now, there is nothing.
Here is the DataModel class
using System.Collections.Generic;
namespace APITestProject
{
class DataModel
{
public class Camera
{
public int id { get; set; }
public string name { get; set; }
public int rover_id { get; set; }
public string full_name { get; set; }
}
public class Rover
{
public int id { get; set; }
public string name { get; set; }
public string landing_date { get; set; }
public string launch_date { get; set; }
public string status { get; set; }
}
public class Photo
{
public int id { get; set; }
public int sol { get; set; }
public Camera camera { get; set; }
public string img_src { get; set; }
public string earth_date { get; set; }
public Rover rover { get; set; }
}
public class Example
{
public IList<Photo> photos { get; set; }
}
}
}
Any suggestions would be greatly appreciated.
Edit #1: Here is the first 3 entries in the json. I didn't want to post the whole thing but the URL is valid for anyone to run and see the response.
{"photos":[{"id":424926,"sol":1000,"camera":{"id":22,"name":"MAST","rover_id":5,"full_name":"Mast Camera"},"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631200305217E01_DXXX.jpg","earth_date":"2015-05-30","rover":{"id":5,"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active"}},{"id":424927,"sol":1000,"camera":{"id":22,"name":"MAST","rover_id":5,"full_name":"Mast Camera"},"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000MR0044631190503679E04_DXXX.jpg","earth_date":"2015-05-30","rover":
Edit #2: I made some changes based on the comments so far and I used the Paste > Special > JSON as Classes and removed the "wrapper" class. Now I get the populated object. FYI, here is the new class VS generated:
namespace APITestProject
{
public class DataModel
{
public Photo[] photos { get; set; }
}
public class Photo
{
public int id { get; set; }
public int sol { get; set; }
public Camera camera { get; set; }
public string img_src { get; set; }
public string earth_date { get; set; }
public Rover rover { get; set; }
}
public class Camera
{
public int id { get; set; }
public string name { get; set; }
public int rover_id { get; set; }
public string full_name { get; set; }
}
public class Rover
{
public int id { get; set; }
public string name { get; set; }
public string landing_date { get; set; }
public string launch_date { get; set; }
public string status { get; set; }
}
}
Can you try the following amendment
var result = JsonSerializer.Deserialize<DataModel.Example>(response);
as it looks like DataModel.Example is actually the class that you are trying to deserialize to based on the response that comes from the following call -
https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=1000&page=2&api_key=DEMO_KEY
i.e. It returns an object containing an array of photo objects as you have defined them. As someone else mentioned, no need to encapsulate all of these classes within another class.
You class DataModel just defines other classes, but do not instance them.
According to the data inside the response, you DataModel class should have at least Photos member. It could be type of List<Photo>
class DataModel {
...
public List<Photo> Photos { get; set; }
}
The Photos definition says, that there is some list of photos of Photo type to be expected.

Geocoding REST call C# Parsing JSON

I'm struggling to pick up the data returned from the Geocoding REST call below (I've removed my app_id and app_code so you cannot run the url as it is below):
https://geocoder.api.here.com/6.2/geocode.json?app_id=[MY APP ID]&app_code=[MY APP CODE]&searchtext=chester
An example reponse can be found here:
https://developer.here.com/documentation/geocoder/topics/quick-start-geocode.html
I know it returns results but I cannot seem to get the results through to my C# application, I don't know if I'm building the class system incorrectly or whether there's something else I'm doing wrong. I've built an application reading the places api with no problem before but this one seems different somehow.
The call returns with a status of OK:
public void GeoCode()
{
// BUILD INITIAL STRING BASED ON PARAMETERS
string url = "https://geocoder.api.here.com/6.2/geocode.json?app_id=gpZ1Ym7rwuXs6Xj1TsD8&app_code=4UXmaGFTe30LttFgOY7iqQ&searchtext=" + tbLoc.text;
// RUN THE ASYNCRONOUS COMMAND (I THINK)
StartCoroutine(GetText(url));
}
IEnumerator GetText(string url)
{
// CREATE WEB REQUEST WITH SPECIFIED URL
UnityWebRequest www = UnityWebRequest.Get(url);
// RETURN RESULTS FROM ASYNC COMMAND
yield return www.SendWebRequest();
// PARSE JSON RESPONSE
RootObject RootObject = JsonUtility.FromJson<RootObject>(www.downloadHandler.text);
// IF 200 (STATUS OKAY) GATHER RESULTS, ELSE RETURN ERROR
if (www.responseCode == 200)
{
BuildArray(RootObject);
}
else
{
Debug.Log("Call Failed With Error: " + www.responseCode.ToString());
}
}
private void BuildArray(RootObject RootObject)
{
print(RootObject.Response.View[0].Result[0].Location.Address.Label);
}
It attempts to run the BuildArray function but this returns a null reference. (I'm just using the NextPageInformation as the most basic option to test)
Below is the class structure I have built to deal with the JSON:
public class Address
{
public string Label { get; set; }
}
public class Location
{
public Address Address { get; set; }
}
public class Result
{
public Location Location { get; set; }
}
public class View
{
public List<Result> Result { get; set; }
}
public class Response
{
public List<View> View { get; set; }
}
public class RootObject
{
public Response Response { get; set; }
}
Can someone please help?
Thank you
If you want to parse only one key value pair from json then creating class structure will tedious job for you.
Instead of creating class structure you can Querying a json with Newtonsoft.
Parse your json.
Querying your parsed json to retrieve Label
value.
//1
JToken jToken = JToken.Parse(jsonString);
//2
string label = jToken["Response"]["View"][0]["Result"][0]["Location"]["Address"]["Label"].ToObject<string>();
Console.WriteLine(label);
Console.ReadLine();
Output: (from your sample json provided in link)
Note: You need to install newtonsoft.json package from nuget and add below namespace to your program.
using Newtonsoft.Json.Linq;
Edit:
If you want parsed your full json then first create a class structure like below
public class MetaInfo
{
public DateTime Timestamp { get; set; }
}
public class MatchQuality
{
public int City { get; set; }
public List<double> Street { get; set; }
public int HouseNumber { get; set; }
}
public class DisplayPosition
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class NavigationPosition
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class TopLeft
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class BottomRight
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class MapView
{
public TopLeft TopLeft { get; set; }
public BottomRight BottomRight { get; set; }
}
public class AdditionalData
{
public string value { get; set; }
public string key { get; set; }
}
public class Address
{
public string Label { get; set; }
public string Country { get; set; }
public string State { get; set; }
public string County { get; set; }
public string City { get; set; }
public string District { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
public string PostalCode { get; set; }
public List<AdditionalData> AdditionalData { get; set; }
}
public class Location
{
public string LocationId { get; set; }
public string LocationType { get; set; }
public DisplayPosition DisplayPosition { get; set; }
public List<NavigationPosition> NavigationPosition { get; set; }
public MapView MapView { get; set; }
public Address Address { get; set; }
}
public class Result
{
public int Relevance { get; set; }
public string MatchLevel { get; set; }
public MatchQuality MatchQuality { get; set; }
public string MatchType { get; set; }
public Location Location { get; set; }
}
public class View
{
public string _type { get; set; }
public int ViewId { get; set; }
public List<Result> Result { get; set; }
}
public class Response
{
public MetaInfo MetaInfo { get; set; }
public List<View> View { get; set; }
}
public class RootObject
{
public Response Response { get; set; }
}
And then you can deserialized your json like.
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
Note: You need to add below namespace to your program.
using Newtonsoft.Json;
I personally had problems parsing nested json objects with JsonUtility. So I switched to Newtonsoft Json and it works really well.
In your case you need to mark the classes as serialized using [Serializable] see here
[Serializable]
public class Address
{
public string Label;
}

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.

Windows Phone Parse json data? from Url with user input?

I Followed this to Create Restful Web Services which display JSON as OutPut from the MySQL Data base.
I Successfully Done it, But Here I Have nearly 100 Tables in Database with different name
And I am Getting This kind of Json Data
{"WindowsResult":[{"ID":9,"TYPE":"WindowsPhone","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post1.jpg"}],"success":3}
this another result
{"SonyResult":[{"ID":3,"TYPE":"SonyXperia","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post2.jpg"}],"success":3}
this another one
{"SamsungResult":[{"ID":1,"TYPE":"Samsung","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post3.jpg"}],"success":3}
For this I am parsing a JSON data form a url
like localhost/Service1.svc/windows or localhost/Service1.svc/sony like that
Here it should Take with a user input..
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
string Data = txtData.Text;
string ServiceUri = "http://lhost:30576/Service1.svc/"
+ "Data" + "/";
WebClient proxy = new WebClient();
proxy.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(proxy_DownloadStringCompleted);
proxy.DownloadStringAsync(new Uri(ServiceUri));
}
But I am Confused at Here
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var rootObject = JsonConvert.DeserializeObject<RootObject>(e.Result);
foreach (var TYPE in rootObject.SonyResult)
{
Console.WriteLine(type.TITLE);
}
}
what should be at Root object
for some Results I have SamsungResult as Root Object like that.
Please suggest Me Regarding this..
Update
when I enter the a url like http://www.google.com/service1.scv/sony
I am getting
{"SonyResult":[{"ID":3,"TYPE":"SonyXperia","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post2.jpg"}],"success":3}
like that every brand I have one result Not All in one string..
K bro the problem is in your json data
{"Mobiles":[
{"SonyResult":[{"ID":3,"TYPE":"SonyXperia","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post2.jpg"}],"success":3},
{"WindowsResult":[{"ID":9,"TYPE":"WindowsPhone","TITLE":"XYZ","PRICE":"$0","IMAGE":"Post1.jpg"}],"success":3}
]}
Since you hadn't specified a Root object name for our tables so json was using your table names as root objects.
Its C# class will be
public class SonyResult
{
public int ID { get; set; }
public string TYPE { get; set; }
public string TITLE { get; set; }
public string PRICE { get; set; }
public string IMAGE { get; set; }
}
public class WindowsResult
{
public int ID { get; set; }
public string TYPE { get; set; }
public string TITLE { get; set; }
public string PRICE { get; set; }
public string IMAGE { get; set; }
}
public class Mobile
{
public List<SonyResult> SonyResult { get; set; }
public int success { get; set; }
public List<WindowsResult> WindowsResult { get; set; }
}
public class RootObject
{
public List<Mobile> Mobiles { get; set; }
}
Hope that solved your problem.
Update
For ur received query the C# class is going to be
public class SonyResult
{public int ID { get; set; }
public string TYPE { get; set; }
public string TITLE { get; set; }
public string PRICE { get; set; }
public string IMAGE { get; set; }
}
public class RootObject
{
public List<SonyResult> SonyResult { get; set; }
public int success { get; set; }
}
Now since for each different models you are getting different queries where each are an array of its own with no common object name. So for each different model the root object class will differ.
I havent tried it as I dont have access to your code but try if this format works(Since I havent tried this so I have my doubts if this will work or not).
public class SonyResult
{
public int ID { get; set; }
public string TYPE { get; set; }
public string TITLE { get; set; }
public string PRICE { get; set; }
public string IMAGE { get; set; }
}
public class WindowsResult
{
public int ID { get; set; }
public string TYPE { get; set; }
public string TITLE { get; set; }
public string PRICE { get; set; }
public string IMAGE { get; set; }
}
public class RootObject
{
public List<SonyResult> SonyResult { get; set; }
public int success { get; set; }
public List<WindowsResult> WindowsResult { get; set; }
}

Retrieving values of fields in a list

I have the class "Alerts", which contains some returned information from Wunderground's API. I then have another class inside "Alerts", "Alert". My code looks like this:
public class Alerts
{
public class Features
{
public int alerts { get; set; }
}
public class Response
{
public string version { get; set; }
public string termsofService { get; set; }
public Features features { get; set; }
}
public class ZONED
{
public string state { get; set; }
public string ZONE { get; set; }
}
public class StormBased
{
}
public class Alert
{
public string type { get; set; }
public string description { get; set; }
public string date { get; set; }
public string date_epoch { get; set; }
public string expires { get; set; }
public string expires_epoch { get; set; }
public string message { get; set; }
public string phenomena { get; set; }
public string significance { get; set; }
public List<ZONED> ZONES { get; set; }
public StormBased StormBased { get; set; }
}
public class RootObject
{
public Response response { get; set; }
public string query_zone { get; set; }
public List<Alert> alerts { get; set; }
}
public class AlertsUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
}
I create a RootObject when the app starts, and later use JSON to empty values. The call returns "response", "query_zone", and "alerts". Now the last one is a List of type Alert, which contains type, description, etc. of an issued alert.
So I have this list stored as alertVar. This has several methods, including count. I can figure out how many alerts are issued, but I'm not sure how to move on.
How do I retrieve the string values (such as type) with this list?
Assuming alertVar is your list of Alert, you can do something like:
string some_string;
foreach (var alert in alertVar)
{
some_string += alert.type + ", ";
}
This will add all the types to a long string (some_string).
You can do the same for whichever property you want ...
foreach (var alert in alerts)
{
var type = alert.type;
var description = alert.description
}
That is a basic example of how you use the item you are looping over.

Categories

Resources