Having trouble accessing a response back from a rest API service that has nested property.
For example here's the raw REST response:
"count": 5,
"results": [
{
"suggestion": "1 Wonston Road, Southampton, SO16 ...",
"matched": [[ 29, 37 ]],
{
"suggestion": "3 Wonston Road, Southampton, SO16 ...",
"matched": [[ 29, 37 ]],
Suggestion and Match are nested property within results.
The function that gets the response in my code is
IRestResponse<SearchResponse> response = client.Execute<SearchResponse>(request); I've used rest sharp here and the call is actually accurate as I get all the data back in form of a raw response.
I've defined the SearchResponse class as
//same for result, match, suggestion.
private string _count;
public string Count
{
get
{
return _count;
}
set
{
_count = value;
}
}
How can I define nested variables to pass them into SearchResponse.suggestion? Currently the nested properties are stored in results.
public class Result {
public string suggestion { get; set; }
public List<List<int>> matched { get; set; }
public string format { get; set; } }
public class RootObject {
public int count { get; set; }
public List<Result> results { get; set; } }
http://json2csharp.com Did the trick, Thank you
Related
Hey all (newbie here) I am developing A Xamarin forms application In which I am already making API requests (Code is Down Below), However, the response I am getting back at the moment looks like this:
{
"result": "success",
"documentation": "https://www.exchangerate-api.com/docs",
"terms_of_use": "https://www.exchangerate-api.com/terms",
"time_last_update_unix": 1673308801,
"time_last_update_utc": "Tue, 10 Jan 2023 00:00:01 +0000",
"time_next_update_unix": 1673395201,
"time_next_update_utc": "Wed, 11 Jan 2023 00:00:01 +0000",
"base_code": "EUR",
"target_code": "GBP",
"conversion_rate": 0.8803
}
I am Only using the conversion rate variable however in the next API I am hoping to use all this variables are stored in parameters (Class I guess?) called Data, so currently, the class I am using to store the variable which is grabbed from this API response looks like this:
public double conversion_rate { get; set; }
So how would I adapt this code to interpret that data, the response is below (I want the data labeled "actual" in the "intensity" section TIA):
"data": [
{
"from": "2023-01-10T19:30Z",
"to": "2023-01-10T20:00Z",
"intensity": {
"forecast": 70,
"actual": 79,
"index": "low"
}
}
]
Ive attempted to find a solution on my own for a while, looked all around and still nothing to see :)
I would create two DTO (data transfer object) classes which contain the properties you're interested in. Once you make the API request, you can map or parse the relevant fields to another object or type.
FYI - you should rename conversion_rate to ConversionRate, which is the standard for property names in C# and then add [JsonPropertyName("conversion_rate")] above the property.
First, you can write the c# class entity based on the json file. Here is the demo and you can refer to.
public class Root
{
public string result { get; set; }
public string documentation { get; set; }
public string terms_of_use { get; set; }
public int time_last_update_unix { get; set; }
public string time_last_update_utc { get; set; }
public int time_next_update_unix { get; set; }
public string time_next_update_utc { get; set; }
public string base_code { get; set; }
public string target_code { get; set; }
public double conversion_rate { get; set; }
}
Then, you can write the method to deserialize the json file.
using System.Text.Json;
var options = new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
var codeRoot = JsonSerializer.Deserialize<Root>(Json, options);
EDIT: Once I have this information deserialized, how can I access the data I need? The only information I need to grab is the TransitTime and the Cost for each accessorial.
I'm working with an API in which I need data from nested objects, but I'm unsure of how to access this information. I've passed my data to the API and have set up new classes based on how the data comes back from the API.
Here's what the response looks like:
{"RatingResponse":
{"Success":"true",
"Message":"",
"QuoteID":"57450",
"LoadNum":"57450",
"Rates":{
"Rate":[
{"SCAC":"TEST",
"CarrierName":"TEST",
"TransitTime":"1",
"ServiceLevel":"D",
"TotalCost":"983.69",
"ThirdPartyCharge":"983.69",
"Accessorials":{
"Accessorial":[
{"Code":"400",
"Cost":"1,655.55",
"Description":"Freight"
},
{"Code":"DSC",
"Cost":"-985.55",
"Description":"Discount"
},
{"Code":"FUE",
"Cost":"313.69",
"Description":"Fuel Surcharge"
}
]
},
"QuoteNumber":""
},
{"SCAC":"TEST2",
"CarrierName":"TEST2",
"TransitTime":"1",
"ServiceLevel":"D",
"TotalCost":"983.69",
"ThirdPartyCharge":"983.69",
"Accessorials":{
"Accessorial":[
{"Code":"400",
"Cost":"1,655.55",
"Description":"Freight"
},
{"Code":"DSC",
"Cost":"-985.55",
"Description":"Discount"
},
{"Code":"FUE",
"Cost":"313.69",
"Description":"Fuel Surcharge"
}
]
},
"QuoteNumber":""
}
]
},
"AverageTotalCost":"983.69"
}
}
I've converted it to C#:
public class Accessorial
{
public string Code;
public string Cost;
public string Description;
}
public class Accessorials
{
public List<Accessorial> Accessorial;
}
public class Rate
{
public string SCAC;
public string CarrierName;
public string TransitTime;
public string ServiceLevel;
public string TotalCost;
public string ThirdPartyCharge;
public Accessorials Accessorials;
public string QuoteNumber;
}
public class Rates
{
public List<Rate> Rate;
}
public class RatingResponse
{
public string Success;
public string Message;
public string QuoteID;
public string LoadNum;
public Rates Rates;
public string AverageTotalCost;
}
public class Root
{
public RatingResponse RatingResponse;
}
The only values I need are the Rate Transit Time and Service Level as well as the Accessorial Costs. I'm a beginner with APIs and am not sure how to return only that information. Any help is greatly appreciated!
you don't need any classes if you use this code
var rate = (JArray)JObject.Parse(json)["RatingResponse"]["Rates"]["Rate"];
var result = rate.Select(r => new
{
TransitTime = (int)r["TransitTime"],
ServiceLevel = (string) r["ServiceLevel"],
AccessorialCost = ((JArray)r["Accessorials"]["Accessorial"]).Select(r => (double)r["Cost"]).ToList()
});
result (in json format)
[
{
"TransitTime": 1,
"ServiceLevel": "D",
"AccessorialCost": [
1655.55,
-985.55,
313.69
]
},
{
"TransitTime": 1,
"ServiceLevel": "D",
"AccessorialCost": [
1655.55,
-985.55,
313.69
]
}
]
or you can create a Data class instead of an anonymous
List<Data> result = rate.Select(r => new Data
{
....
}).ToList();
public class Data
{
public int TransitTime { get; set; }
public string ServiceLevel { get; set; }
public List<double> AccessorialCost { get; set; }
}
I like #Serge's answer but I prefer to have results in a class because "I only need..." never holds for very long, right? Here is a good discussion of loading the JSON into a complex object:
Your JSON erred in JSON2C#.com but essentially your root object needs the other classes. Something like
public class Root
{
public RatingResponse RatingResponse;
public Rates Rates;
public Accessorials Accessorials;
}
and then deserialize into your complex object
JsonConvert.DeserializeObject<RootObject>(json)
I'm doing this off the top of my head so forgive any syntax errors.
I'm working on a project to gather data from NOAA. I'm having trouble figuring out how to make the response usable.
This is what NOAA's API response looks like to my call:
{
"metadata": {
"resultset": {
"offset": 1,
"count": 38859,
"limit": 2
}
},
"results": [
{
"mindate": "1983-01-01",
"maxdate": "2019-12-24",
"name": "Abu Dhabi, AE",
"datacoverage": 1,
"id": "CITY:AE000001"
},
{
"mindate": "1944-03-01",
"maxdate": "2019-12-24",
"name": "Ajman, AE",
"datacoverage": 0.9991,
"id": "CITY:AE000002"
}
]
}
I used JSON2CSharp.com to convert the result set into my needed classes. Below is the relevant code:
public class NOAA
{
public class Resultset
{
public int offset { get; set; }
public int count { get; set; }
public int limit { get; set; }
}
public class Metadata
{
public Resultset resultset { get; set; }
}
public class Location
{
public string mindate { get; set; }
public string maxdate { get; set; }
public string name { get; set; }
public double datacoverage { get; set; }
public string id { get; set; }
}
public class RootObject
{
public Metadata metadata { get; set; }
public List<Location> results { get; set; }
}
public class Response
{
IList<Metadata> metadata;
IList<Location> results;
}
public void RestFactory(string Token, string Endpoint, Dictionary<string, string> Params)
{
// Initiate the REST request
var client = new RestClient("https://www.ncdc.noaa.gov/cdo-web/api/v2/" + Endpoint);
var request = new RestRequest(Method.GET);
// Add the token
request.AddHeader("token", Token);
// Add the parameters
foreach (KeyValuePair<string, string> entry in Params)
{
request.AddParameter(entry.Key, entry.Value);
}
// Execute the REST request
var response = client.Execute(request);
// Deserialize the response
Response noaa = new JsonDeserializer().Deserialize<Response>(response);
// Print to console
foreach (Location loc in noaa)
{
Console.WriteLine(loc.name);
}
}
}
At this point, I'm just trying to print the location name to reach my next learning milestone. I'm getting the error:
Severity Code Description Project File Line Suppression State
Error CS1579 foreach statement cannot operate on variables of type 'NOAA.Response' because 'NOAA.Response' does not contain a public instance definition for 'GetEnumerator'
Other than the error, I think I don't quite understand the proper approach since the response has more than one "layer". Guidance?
Your foreach loop is trying to call an iterator on the object itself, not the list inside it.
Try this instead
foreach (Location loc in noaa.results)
{
Console.WriteLine(loc.name);
}
I can tell you the cause of error. That is because noaa is not iterable. If you want to iterate over any object then it needs to implement IEnumerable interface. This is the reason because of which noaa is not iterable. noaa does not inherit this interface or implement it. Do you get the same error if you use noaa.results?
I'm trying to extract the values of "name" and "score" from the below JSON response:
"categories": [
{
"name": "people_",
"score": 0.6640625
},
{
"name": "people_portrait",
"score": 0.33203125
}
]
My current C# code to manage this is:
public class Category
{
public string name { get; set; }
public double score { get; set; }
}
...
string contentString = await response.Content.ReadAsStringAsync();
var r = JsonConvert.DeserializeObject<Category>(contentString);
Console.WriteLine(r.name);
Console.WriteLine(r.score);
Console.ReadLine();
But when I try and print the result to the console a blank response is given. I have also check the debugger and name is populated with null and score is populated with 0.
Any help with this would be much appreciated!
In json string, categories is an list of JObjects, so you can use #Roman's approach to solve your problem or try mine,
Here is my approach,
Create one root class called as Categories,
public class Categories
{
[JsonProperty(PropertyName = "categories")]
public List<Category> ListOfCategory {get; set;}
}
Your Category class,
public class Category
{
public string Name { get; set; }
public double Score { get; set; }
}
Now, deserialize using below code
var categories = JsonConvert.DeserializeObject<Categories>(contentString);
Now you can iterate though ListOfCategory,
foreach(var item in categories.ListOfCategory)
{
Console.WriteLine($"Name : {item.Name} \t Score: {item.Score}");
}
POC: .Net Fiddle
I'm trying to use NewtonSoft.Json deserializer, but I don't know if what I'm trying to do is doable, cuase every example of collections that I've seen are like this:
public class ItemRecords
{
public List<ItemRecords> Items { get; set; }
...
}
And what I want is something that looks like as it's explained below...
I have this two classes:
public class ItemRecords : Collection<ItemRecord>
{
[JsonProperty("property1")]
public int Property1 { get; set; }
[JsonProperty("property2")]
public int Property2 { get; set; }
}
public class ItemRecord
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("item_prop1")]
public string ItemProp1 { get; set; }
...
}
I get this json back from my api:
{
property1: 25,
property2: 27,
item_record: [
{
id: 241,
item_prop1: "0.132",
item_prop2: "78787",
...
},
{
id: 242
item_prop1: "1212",
item_prop2: "3333",
...
}
...
]
}
ItemRecords is a collection of ItemRecord.
I tried by adding the JsonArray attribute to the ItemRecords class as follows:
[JsonArray(ItemConverterType = typeof(ItemRecord))]
public class ItemRecords : Collection<ItemRecord> { ... }
Here is the method that executes the request:
private static async Task<T> MakeRequest<T>(string urlRequest)
{
try
{
HttpWebRequest request = WebRequest.Create(urlRequest) as HttpWebRequest;
using (WebResponse response = await request.GetResponseAsync())
{
using (Stream stream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(stream);
string line = string.Empty;
StringBuilder sb = new StringBuilder();
while ((line = reader.ReadLine()) != null)
{
sb.Append(line);
}
T objectDeserialized = JsonConvert.DeserializeObject<T>(sb.ToString());
return objectDeserialized;
}
}
}
catch (Exception ex)
{
return default(T);
}
}
And call to this method looks like this:
...
return await MakeRequest<ItemRecords>(request);
I don't really know what else to do..
Any help would be appreciated.
Your basic difficulty is that the JSON standard has two types of container:
The object which is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Json.NET maps dictionaries and non-enumerable POCOS to objects by default, using reflection to map c# properties to JSON properties.
In the JSON you are getting back from your API, the outermost container is an object.
The array which is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma). Json.NET maps non-dictionary enumerables to arrays by default, serializing each collection item as an array entry.
In the JSON you are getting back from your API, the value of the item_record property is an array.
As a collection with properties, your ItemRecords cannot be mapped to either of these constructs automatically without losing data. Since Json.NET serializes collections as arrays by default, you will need to manually inform it that your type is to be serialized as an object by applying the [JsonObject] attribute. Then, introduce a synthetic item_record property to serialize and deserialize the collection items. Since you are inheriting from Collection<T>, you can use Collection<T>.Items for this purpose:
[JsonObject(MemberSerialization.OptIn)]
public class ItemRecords : Collection<ItemRecord>
{
[JsonProperty("property1")]
public int Property1 { get; set; }
[JsonProperty("property2")]
public int Property2 { get; set; }
[JsonProperty("item_record")]
IList<ItemRecord> ItemRecordList
{
get
{
return Items;
}
}
}
Using MemberSerialization.OptIn prevents base class properties such as Count from being serialized.
Sample fiddle.
As an aside, I don't particularly recommend this design, as it can cause problems with other serializers. For instance, XmlSerializer will never serialize collection properties; see here or here. See also Why not inherit from List?.
Simply add a List<ItemRecord> Records property to class ItemRecords:
public class ItemRecords
{
[JsonProperty("property1")]
public int Property1 { get; set; }
[JsonProperty("property2")]
public int Property2 { get; set; }
[JsonProperty("item_record")]
public List<ItemRecord> Records { get; set; }
}
This looks like you can have a dynamic number of results of properties and item properties like:
{
property1: 25,
property2: 27,
property3: 30,
item_record: [
{
id: 241,
item_prop1: "0.132",
item_prop2: "78787"
},
{
id: 242
item_prop1: "1212",
item_prop2: "3333",
item_prop3: "3333",
item_prop4: "3333",
}
] }
If this is the case, the best option in my opinion will be to change the structure to something like:
{
properties:[
25,
27,
30
],
itemRecords:[
{
id: 27,
itemProperties:[
"321",
"654",
"564"
]
},
{
id: 25,
itemProperties:[
"321",
"654"
]
},
]
}