Parse single values from HttpResponse - c#

In making a call to the Google Geolocation API, the results (json) are returned like so
Example (Apologies, I couldn't get the Json to format properly)
{"geocoded_waypoints" : [
{
"geocoder_status" : "OK",
"place_id" : "EiQ3LCA3IExha2VzaWRlIERyLCBSeWUsIE5ZIDEwNTgwLCBVU0EiHRobChYKFAoSCQH00P0vl8KJEQ2d7mWAl0jrEgE3",
"types" : [ "subpremise" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJ1YqpR4eRwokRTuazxMrnKiM",
"types" : [ "establishment", "point_of_interest" ]
} ],
"routes" : [{
"bounds" : {
"northeast" : {
"lat" : 41.0044903,
"lng" : -73.6892836
},
"southwest" : {
"lat" : 40.9575099,
"lng" : -73.7589093
}
},
"copyrights" : "Map data ©2018 Google",
"legs" : [
{
"distance" : {
"text" : "7.0 mi",
"value" : 11325
},
"duration" : {
"text" : "15 mins",
"value" : 889
},
"end_address" : "851 Fenimore Rd, Mamaroneck, NY 10543, USA",
"end_location" : {
"lat" : 40.9575099,
"lng" : -73.75338219999999
},
"start_address" : "7 Pheasant Run #7, Rye, NY 10580, USA",
"start_location" : {
"lat" : 40.99850199999999,
"lng" : -73.689633
},
There are various single items I need to retrieve from the returned data, for example, the duration:text value.
Is there a way to filter out the excess in the API call or how do I parse this from the Json?
I tried deserializing to an object to then iterate over it and grab the legs array, but A. that doesn't work as the object is on big item, not a collection and B. that seems wasteful.
public int TravelTimeInMinutes(string origin, string destination, string apiKey)
{
var timeToTravel = 0;
var url = DirectionsUrlBase + ConvertOriginFormat(origin) + ConvertDestinationFormat(destination) + "&key="+ apiKey;
var client = new HttpClient();
// Add the Accept type header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
// get the response
// make method async once working
var response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
// Parse the response body.
var result = JsonConvert.SerializeObject(response.Content.ReadAsStringAsync().Result());
dynamic array = JsonConvert.DeserializeObject(result);
foreach (var item in array)
{
}
//… rest removed for brevity
How can I drill down to retrieve single values? I think my error is in how I am deserializing the response. I also have a Duration class with Text and Value properties. I would like to deserialize to that class if possible.
Follow up
I added .Result after the serialize call
response.Content.ReadAsStringAsync().Result()
this is now returning proper json
Now how can I parse single values from this or can I deserialize into the Duration class.
Per Charles suggestion
I have a root object
public class MapsDirectionObject
{
public GeocodedWaypoints[] geocoded_waypoints { get; set; }
public Routes[] routes { get; set; }
}
public class Routes
{
public object[] Value { get; set; }
}
public class GeocodedWaypoints
{
public string geocoder_status { get; set; }
public string place_id { get; set; }
public string[] types { get; set; }
}
And since the returned json only has two main children, routes and waypoints, I have those classes as well. The deserialization errors with the following error.
Newtonsoft.Json.JsonSerializationException: 'Error converting value "{ "geocoded_waypoints" : [
{
If I remove the .Result call on the serialization, I can map to that object but the values are null.

first of all I'd prefer we do strongly typed deserialization, so let's create classes corresponding to the data we need from the JSON:
public class ResultData
{
[JsonProperty("routes")]
public List<Route> Routes { get; set; }
}
public class Route
{
[JsonProperty("legs")]
public List<Leg> Legs { get; set; }
}
public class Leg
{
[JsonProperty("duration")]
public Duration Duration { get; set; }
}
public class Duration
{
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("value")]
public int Value { get; set; }
}
then we deserialize the JSON:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("https://maps.googleapis.com/maps/api/directions/json?origin=7+7+Lakeside+Dr+Rye+NY&destination=Winged+Winged+Foot+Golf+Club").Result;
if (response.IsSuccessStatusCode)
{
var desed = JsonConvert.DeserializeObject<ResultData>(response.Content.ReadAsStringAsync().Result);
var durations = desed.Routes.SelectMany(r => r.Legs.Select(l => l.Duration)).ToList();
durations.ForEach(d => Console.WriteLine($"T: {d.Text}, V: {d.Value}"));
}
Note:
skip the serialization step ... ReadAsStringAsync() should produce a valid JSON string

First of all, please post a complete valid JSON object on your answer.
You uses Visual Studio for coding right? You can use Paste Special for help you:
1) Copy your entire JSON to clipboard;
2) Open your class file on Visual Studio;
3) Go to menu "Edit > Paste Special > Paste as JSON Class";
4) You will got something like this:
public class Rootobject
{
public Geocoded_Waypoints[] geocoded_waypoints { get; set; }
}
public class Geocoded_Waypoints
{
public string geocoder_status { get; set; }
public string place_id { get; set; }
public string[] types { get; set; }
}
Now you can deserialize to a typed object:
var myObject = JsonConvert.DeserializeObject<Rootobject>(result);
foreact(var geocoded_waypoints in myObject.geocoded_waypoints)
{
// do something with geocoded_waypoints
}
// your duration object:
var duration = myObject.routes[0].legs[0].duration;
If you want you can rename Rootobject to any name you want, like Geolocation.

Related

Deserializing an array of objects: The JSON value could not be converted to System.String[]

Can't access objects inside the array using JSON.Net
public class VoskReturnArray
{
public string[] result { get; set; }
public string text { get; set; }
}
var voskArray = JsonSerializer.Deserialize<VoskReturnArray>(rec.Result());
Console.WriteLine(voskArray.text); // Works fine
Console.WriteLine(voskArray.result); // Throws an exception
Tried with <List<VoskReturnArray>>, but then text won't show up.
What am I missing here?
Data:
{
"result" : [{
"conf" : 0.228337,
"end" : 0.141508,
"start" : 0.060000,
"word" : "one"
}, {
"conf" : 1.000000,
"end" : 0.390000,
"start" : 0.141508,
"word" : "hundred"
}, {
"conf" : 1.000000,
"end" : 1.080000,
"start" : 0.390000,
"word" : "employees"
}],
"text" : "one hundred employees that's where it is you know they had the same problems are those five employees companies but they have the money to pay to fix them"
}
Your data shows result as an array of objects, while your result property in VoskReturnArray model is an array of string. It should be instead an array of a model type for those objects. So rather than:
public string[] result { get; set; }
You'd want something like:
public ResultItem[] result { get; set; }
...
public class ResultItem
{
public decimal conf { get; set; }
public decimal end { get; set; }
// etc
}

Inconsistent JSON

I am trying to parse JSON in C# which is inconsistent, i.e
Below are the example of JSON that I am getting.
{
"Timestamp" : "2019-05-09T11:24:25.000Z",
"Channel" : "web",
"Supplier" : "kunde",
"Generator" : "survey",
"Type" : "hudtest",
"Data" :{
"Alder" : "20-29",
"Køn" : "Kvinde",
"Hudtype" : "sensitiv",
"Hudtilstand" : "mixet"
}
}
and variation of this JSON is like this:
{
"Timestamp" : "2019-05-09T11:24:25.000Z",
"Channel" : "web",
"Supplier" : "kunde",
"Generator" : "survey",
"Type" : "hudtest",
"Data" :{
"Alder" : "20-29",
"Køn" : "Kvinde",
"Hudtype" : "sensitiv",
"Hudtilstand" : "mixet",
"materialistID" : 61234,
  "Anbefalede produkter" : [ 100225, 725125 ]
}
}
As you can see in both example I have different values in Data key. How can I parse this JSON in C#?
FYI: The Data key can have different value from the example i shared above. Not only "Anbefalede produkter. It can contain number of different values.
I have tried making it dynamic or parsing into anonymous type as well. But I also want to validate my JSON schema, Except Data Key other keys must be validated and they are mandatory.
You can do like this
class Program
{
static void Main(string[] args)
{
string jsonData = #"{ 'Timestamp': '2019-05-09T11:24:25.000Z',
'Channel': 'web',
'Supplier': 'kunde',
'Generator': 'survey',
'Type': 'hudtest',
'Data': {
'Alder': '20-29',
'Køn': 'Kvinde',
'Hudtype': 'sensitiv',
'Hudtilstand': 'mixet',
'materialistID': 61234,
'Anbefalede produkter': [100225, 725125]
}
}";
var b = JsonConvert.DeserializeObject<Rootobject>(jsonData);
//Console.WriteLine(b.Data.Hudtype);
//or
Console.WriteLine(b.Data["Hudtype"]);
Console.ReadKey();
}
}
public class Rootobject
{
public DateTime Timestamp { get; set; }
public string Channel { get; set; }
public string Supplier { get; set; }
public string Generator { get; set; }
public string Type { get; set; }
public Dictionary<string, object> Data { get; set; }
}
Hope this will solve your problem.
Thanks

Retrieve data from JSON using JObject

I am attempting to get a value for a game from JSON, but there are multiple fields with the same name, so I was wondering whether there was a way in which I could just retrieve that individual value, here is the basic JSON structure:
"response": {
"game_count": 119,
"games": [
{
"appid": 3920,
"playtime_forever": 0
},
{
"appid": 4000,
"playtime_forever": 278
},
...
I need to somehow get a property by using an appID and then retrieving the playtime_forever key.
You can convert your JSON to class and then query:
class ResponseJSON
{
[JsonProperty("response")]
public Result Response { get; set; }
}
class Result
{
[JsonProperty("game_count")]
public string Count { get; set; }
[JsonProperty("games")]
public List<Game> Gmaes { get; set; }
}
class Game
{
[JsonProperty("appid")]
public string Id { get; set; }
[JsonProperty("playtime_forever")]
public string PlayTime { get; set; }
}
var resp = JsonConvert.DeserializeObject<ResponseJSON>(jsonstr);
And then you can iterate through your object with a for loop:
foreach(game in resp.Respone.Games) {
var playtime = game.PlayTime;
// do stuff here
}
Or you can use linq to query your games:
var selectiveGames = resp.Response.Games.Where(x=> x.PlayTime == 220).ToList();
You need to add newtonsoft dll from here to your project if you don't have it;
UPDATE: With original JSON the code above is working perfect.

C# - Newtonsoft : Generic class for Client Response

After hours of attempts and research, I am asking for your help.
I am calling a public API which returns the same structure except for the datas returned.
For examples, the REST calls which retrieve stations and districts return those two JSON answers :
Stations response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : {
"station": [{
"number": "stationId",
"name": "stationName",
"address": "stationAddress",
"state": "1",
"latitude": "stationLat",
"longitude": "stationLong",
"slotsavailable": "10",
"bikesavailable": "20",
"pos": "0",
"district": "stationDistrict",
"lastupdate": "2016-03-28T11:47:08+02:00"
}, {...}, ...]}
}
Districts response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : { "district": [{"id": "districtId", "name": "districtName"}, {...}, ...] }
}
I am using a .NET 4.5/C# solution with Newtonsoft.Json to execute the call.
I want to make the object, mapped to the client response, generic so the execution of the call will be made as follow :
var result = await client.Execute<Response<ApiResponseDistrict>>(request);
var result = await client.Execute<Response<ApiResponseStation>>(request);
My first attempt was to make a non generic call (create a full object by returned datas) which was a success.
My second attempt was to created a generic object so I made the following classes using the JsonProperty of the library Newtonsoft :
public class ApiResponse<T>
{
[JsonProperty("response")]
public Response<T> Response { get; set; }
}
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
public class ApiResponseDistrict
{
[JsonProperty("district")]
public List<District> Districts { get; set; }
}
public class District
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
At this point, when I am executing the call the object Response is valorized and also its property Status with the value waited but the property Data is never valorized (null).
My third attempt was to continue on the second attempt but using the JsonObject of the Newtonsoft library which it's given (with the same result) :
[JsonObject("district")]
public class ApiResponseDistrict
{
public List<District> Districts { get; set; }
}
As I am new to Newtonsoft, I would like to know if it is possible to use generic classes, as I am trying to do, to mapped the object returned by the call or I have to create a complete object for each "data" returned ?
Thank you for your answer and explanations or clues for me to find the answer !
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
This adds another layer between the data, so a response would look like this:
{
"Status": …,
"Data": {
"ResponseData": {
<The actual type T>
}
}
}
Instead, you want to remove that ResponseData level:
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
}
So for example, for the JSON above, you would have a StationResponseData class:
public class StationResponseData
{
public List<Station> Stations
{ get; set; }
}
And then you would deserialize the JSON as Response<StationResponseData>. The Station class would then contain those properties for number, name, address, etc.

Json Deserialize in C#

How to use JsonConvert.DeserializeObject with below Json
[{
"attributes" : {
"type" : "User",
"url" : "/xx/xx/xx"
},
"Id" : "1",
"Name" : "abc"
},{
"attributes" : {
"type" : "User",
"url" : "/xx/xx/xx"
},
"Id" : "2",
"Name" : "abc"
},{
"attributes" : {
"type" : "User",
"url" : "/xx/xx/xx"
},
"Id" : "3",
"Name" : "abc"
}]
These are my class
public class Attributes
{
public string type { get; set; }
public string url { get; set; }
}
public class RootObject
{
public Attributes attributes { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
I have tried with
var c = JsonConvert.DeserializeObject <RootObject>(jsonText);
Your Json actually represents an array of RootObject instances. Try this:
var c = JsonConvert.DeserializeObject<RootObject[]>(jsonText);
Or possibly
var c = JsonConvert.DeserializeObject<List<RootObject>>(jsonText);
Or even
var c = JsonConvert.DeserializeObject<IEnumerable<RootObject>>(jsonText);
Your JSON is actually an array, so try deserializing it into RootObject[]:
var c = JsonConvert.DeserializeObject<RootObject[]>(jsonText);
You json is a array (or collection), try to deserialize it using the array type:
var c = JsonConvert.DeserializeObject<RootObject[]>(jsonText);
Or any other type of collection, for sample:
var c = JsonConvert.DeserializeObject<IEnumerable<RootObject>>(jsonText);
var c = JsonConvert.DeserializeObject<ICollection<RootObject>>(jsonText);
Try telling the deserializer what you're expecting to deserialize to, in this case RootObject.
According to the documentation of the method you're currently calling JsonConvert.DeserializeObject Method (String) returns a .net object.
While this method JsonConvert.DeserializeObject<T> Method (String) returns the specified type.
for example:
public class Attributes
{
public string type { get; set; }
public string url { get; set; }
}
public class RootObject
{
public Attributes attributes { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
RootObject c = JsonConvert.DeserializeObject<RootObject>(jsonText);

Categories

Resources