I have an object that has a property which is a List of other custom objects.
It actually drills down many tiers of custom object properties, but let's just look at the last 3 levels of the object.
{
"version" : {
"version_data" : [ {
"version_value" : "6.06"
}, {
"version_value" : "7.10"
}, {
"version_value" : "8.04"
}, {
"version_value" : "8.10"
} ]
}
}
So my classes look like so:
public class Version
{
[Required()]
public Version_Data version_data { get; set; }
}
public class Version_Data
{
[MinLength(1)]
public List<Version_Data_Item> items { get; set; }
}
public class Version_Data_Item
{
[Required()]
public string version_value { get; set; }
}
I was able to extract one version_data_item
{
"version_value" : "6.06"
}
and if I deserialize that JSON I am able to call something like: deserializedObject.version_value and it returns 6.06
The problem I run into is the upper levels. For example, I then extract the "Version_Data" object from the data
{
"version_data" : [ {
"version_value" : "6.06"
}, {
"version_value" : "7.10"
}, {
"version_value" : "8.04"
}, {
"version_value" : "8.10"
} ]
}
that deserializes into a Version_Data (no exceptions raised at least), but when I debug it says the list is null.
What am I missing?
Your version_data should be called items:
{
"items" : [ {
"version_value" : "6.06"
}, {
"version_value" : "7.10"
}, {
"version_value" : "8.04"
}, {
"version_value" : "8.10"
} ]
}
For generation C# from JSON you can use very helpful web generator.
Your correct models are here:
public class VersionData
{
public string version_value { get; set; }
}
public class Version
{
public List<VersionData> version_data { get; set; }
}
public class RootObject
{
public Version version { get; set; }
}
Are you using Newtonsoft's JSON? The structure does not look correct. Unless you use custom parser, the structure should be like this:
https://app.quicktype.io?share=Olvtc5B3C1zg7hy2CJgp
Related
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
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.
I am using entity framework to get data from database and serialize it to JSON. And I want my JSON response looks like the one below.
Shoud I add items property to my model and make JSON I want? Thanks.
Desired Json
{
"items" : [
{
"Id": 1,
"AdContent":"Content1"
},
{
"Id": 2,
"AdContent":"Content2"
},
{
"Id": 3,
"AdContent":"Content3"
}
]
}
Current JSON I receive
[
{
"Id":1,
"AdContent":"Content1"
},
{
"Id":2,
"AdContent":"Content2"
},
{
"Id":3,
"AdContent":"Content3"
}
]
{
Controller
public JsonResult GetJson()
{
using (var db = new DoskaUsContext())
{
List<AdViewModel> list = db.Ads.Select(x => new AdViewModel
{
Id = x.AdId,
AdContent = x.AdContent
}).ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
}
Model
public class AdViewModel
{
public int Id { get; set; }
public string AdContent { get; set; }
}
Anonymous object is one solution Json(new {items=list},...).
General approach to solve that problem - generate strongly typed classes with http://json2csharp.com/ and populate result via generated classes or at least see what is missing from your code.
In this particular case generated code:
public class Item
{
public int Id { get; set; }
public string AdContent { get; set; }
}
public class RootObject
{
public List<Item> items { get; set; }
}
Which shows missing piece of the puzzle - RootObject with list property items.
Create another model which hold collection of AdViewModel as items
public class AdViewModel
{
public int Id { get; set; }
public string AdContent { get; set; }
}
public class NewModel
{
public AdViewModel items { get; set; }
}
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.
I'm using Newtonsoft to deserialize an array of JSON objects. I'm able to successfully deserialize the entire object with the exception of the fully nested #attributes objects.
Here is a snippet of an item I'm trying to parse:
"item" : [{
"title" : "Bloody.Birthday.1981.1080p.BluRay.X264-7SinS",
"guid" : "https:\/\/api.nzb.su\/details\/35e799ce66c3290db629b68e3bac20f9",
"link" : "https://",
"comments" : "https://url",
"pubDate" : "Wed, 25 Jun 2014 12:47:16 -0400",
"category" : "Movies > HD",
"description" : "Bloody.Birthday.1981.1080p.BluRay.X264-7SinS",
"enclosure" : {
"#attributes" : {
"url" : "https://url",
"length" : "6777211483",
"type" : "application\/x-nzb"
}
},
"attr" : [{
"#attributes" : {
"name" : "category",
"value" : "2000"
}
}, {
"#attributes" : {
"name" : "category",
"value" : "2040"
}
}, {
"#attributes" : {
"name" : "size",
"value" : "6777211483"
}
}
]
}
]
Here are my classes to drill down and populate the items:
public class item
{
public string title { get; set; }
public string pubDate { get; set; }
public IList<Attr> attr { get; set; }
}
public class Attr
{
public Attributes attribs { get; set; }
}
public class Attributes
{
public string name { get; set; }
public string value { get; set; }
}
When do I a count on the item.attr, I get the proper # but if I try to actually get the name/value of the Attributes in the list, it gives me a null error. I've done a lot of research and have been unable to determine why it's creating the appropriate items in the List but not the values within the item.
Any thoughts?
Since #attributes is not a valid property name in C#, you need to use a [JsonProperty] attribute to map it to the JSON, e.g.:
public class Attr
{
[JsonProperty("#attributes")]
public Attributes attribs { get; set; }
}