Given:
The classes:
public class Venue
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("location")]
public Location Location { get; set; }
}
public class Location
{
public long Lat { get; set; }
public long Lng { get; set; }
public int Distance { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class Response
{
private List<Venue> _venues;
[JsonProperty("venues")]
public List<Venue> Venues
{
get { return _venues ?? (_venues = new List<Venue>()); }
set { _venues = value; }
}
}
And a response request:
{
"meta":{
"code":200
},
"response":{
"venues":[
{
"id":"4f96a5aee4b01cb74e4dc3c6",
"name":"Centro",
"contact":{
},
"location":{
"address":"Centro",
"lat":-21.256906640441052,
"lng":-48.31978432813259,
"distance":185,
"city":"Jaboticabal",
"state":"SP",
"country":"Brazil",
"cc":"BR"
},
"canonicalUrl":"https:\/\/foursquare.com\/v\/centro\/4f96a5aee4b01cb74e4dc3c6",
"categories":[
{
"id":"4f2a25ac4b909258e854f55f",
"name":"Neighborhood",
"pluralName":"Neighborhoods",
"shortName":"Neighborhood",
"icon":{
"prefix":"https:\/\/foursquare.com\/img\/categories_v2\/parks_outdoors\/neighborhood_",
"suffix":".png"
},
"primary":true
}
],
"verified":false,
"restricted":true,
"stats":{
"checkinsCount":1106,
"usersCount":86,
"tipCount":0
},
"specials":{
"count":0,
"items":[
]
},
"hereNow":{
"count":0,
"groups":[
]
},
"referralId":"v-1376511204"
},
{
"id":"4c38b0b21a38ef3b56b39221",
"name":"Ice by Nice",
"contact":{
},
"location":{
"address":"Jaboticabal Shopping",
"lat":-21.25513775,
"lng":-48.32320093,
"distance":253,
"city":"Jaboticabal",
"state":"SP",
"country":"Brazil",
"cc":"BR"
},
"canonicalUrl":"https:\/\/foursquare.com\/v\/ice-by-nice\/4c38b0b21a38ef3b56b39221",
"categories":[
{
"id":"4bf58dd8d48988d1c9941735",
"name":"Ice Cream Shop",
"pluralName":"Ice Cream Shops",
"shortName":"Ice Cream",
"icon":{
"prefix":"https:\/\/foursquare.com\/img\/categories_v2\/food\/icecream_",
"suffix":".png"
},
"primary":true
}
],
"verified":false,
"restricted":true,
"stats":{
"checkinsCount":656,
"usersCount":309,
"tipCount":15
},
"specials":{
"count":0,
"items":[
]
},
"hereNow":{
"count":2,
"groups":[
{
"type":"others",
"name":"Other people here",
"count":2,
"items":[
]
}
]
},
"referralId":"v-1376511204"
}
]
}
}
When using JSON.NET like so:
Response response = JsonConvert.DeserializeObject<Response>(jsonString);
The deserialized response object has a empty list of venues, What am I doing wrong?
Thanks
There's a bit of a mismatch in what you're trying to deserialize and the class you have defined to deserialize into. You unfortunately need yet another layer of indirection. Note the response has;
// theres an outer object here which contains response
{
"meta":{ "code":200 },
"response":{
// you're trying to deserialize this, but it's not the entire response, it's a property of an anonymous object
}
}
So if I make a new class;
public class ResponseWrapper
{
public object meta;
public Response response;
}
And instead do;
ResponseWrapper response = JsonConvert.DeserializeObject<ResponseWrapper>(jsonString);
Then it will work.
Note that when you're deserializing using json.NET you have to define a structure that exactly matches the json. In this case you're leaving out the outer most object. It is kind of an annoyance and leads to a lot of code like what I just wrote but that's just the way it goes sometimes.
Related
I receive a bill of materials in JSON format via a WebApi, which has a corresponding hierarchy.
The hierarchy or the nesting can be any depth.
An example bill of materials is shown below:
{
"Quantity":0,
"QuantityUnit":"pcs",
"PartNumber":"12345",
"Parent":"",
"Children":[
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"88774",
"Parent":"12345",
"Children":[
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"42447",
"Parent":"88774"
},
{
"Quantity":0.420,
"QuantityUnit":"kg",
"PartNumber":"12387",
"Parent":"88774"
}
]
}
]
}
How can I resolve this nested structure into a simple structure using JSON.NET in C#?
I want to transform it to:
[
{
"Quantity":0,
"QuantityUnit":"pcs",
"PartNumber":"12345",
"Parent":""
},
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"88774",
"Parent":"12345"
},
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"42447",
"Parent":"88774"
},
{
"Quantity":0.420,
"QuantityUnit":"kg",
"PartNumber":"12387",
"Parent":"88774"
}
]
For the deserialization I use the following class:
public class Bom
{
public class TopLevel
{
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
public List<Item> Children { get; set; }
}
public class Item
{
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
}
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
public IList<TopLevel> Children { get; set; }
}
Furthermore, I use this code to deserialize the JSON to an object:
Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));
First let's define a mapper
JObject Map(JObject source)
{
var result = (JObject)source.DeepClone();
result.Remove("Children");
return result;
}
It simply clones the object and removes the Children property
Next let's define a recursive function to accumulate the JObjects
void Flatten(JArray children, JArray accumulator)
{
if (children == null) return;
foreach (JObject child in children)
{
accumulator.Add(Map(child));
Flatten((JArray)child["Children"], accumulator);
}
}
And finally let's make use of them
var semiParsed = JObject.Parse(json);
var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);
The ToString call on the accumulator will return this
[
{
"Quantity": 0,
"QuantityUnit": "pcs",
"PartNumber": "12345",
"Parent": ""
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "88774",
"Parent": "12345"
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "42447",
"Parent": "88774"
},
{
"Quantity": 0.42,
"QuantityUnit": "kg",
"PartNumber": "12387",
"Parent": "88774"
}
]
UPDATE #1
If your source json contains a deep hierarchy (lets say more than 5 levels) then the DeepClone is not really efficient, since you are copying the whole subtree.
To fix this problem you just need to rewrite the Map function
JObject Map(JObject source)
=> JObject.FromObject(new
{
Quantity = (double)source["Quantity"],
QuantityUnit = (string)source["QuantityUnit"],
PartNumber = (string)source["PartNumber"],
Parent = (string)source["Parent"]
});
Deserialize the original list, flatten it with Enumerable.SelectMany, and serialize the resulting sequence.
I was working with a .net core 3.1 Web API. Which is getting data from an external API. Following is my code Controller part
[HttpGet("transinfo/{id}")]
public Object GettransactionData(int id)
{
var result=_transaction.GettransactionDetails(id).Result;
List<PipeLineResponse> P = JsonConvert.DeserializeObject<List<PipeLineResponse>>(result.ToString());
PipeLineResponseObject P1 = new PipeLineResponseObject();
P1.data = P;
return P1;
}
And my service code as follows
public async Task<Object> GettransactionDetails(int id)
{
string request=//fetched from db
var stringContent = new StringContent(request);
Client = utilities.GetHttpClient();
string apiEndpoint=//External API URL
HttpResponseMessage httpResponseMessage = await Client.PostAsync(apiEndpoint, stringContent);
if (httpResponseMessage.IsSuccessStatusCode)
{
return await httpResponseMessage.Content.ReadAsAsync<Object>();
}
}
But i am getting the result in following format (response from postman)
{
"data": [
{
"Tranid": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fields": {
"Fields.10": "1001",
"Fields.11": "Test1",
"Fields.12": "Fixed1"
}
},
{
"Tranid": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fields": {
"Fields.10": "1002",
"Fields.11": "Test2",
"Fields.12": "Fixed2"
}
}
]
}
But i need the data in following format
{
"data": [
{
"TransactionID": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1001"
},
{
"fieldId": "11",
"fieldValue": "Test1"
},
{
"fieldId": "12",
"fieldValue": "Fixed1"
}
]
},
{
"TransactionID": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1002"
},
{
"fieldId": "11",
"fieldValue": "Test2"
},
{
"fieldId": "12",
"fieldValue": "Fixed2"
}
]
}
]
}
How can i achieve this ? is possible to deserialise using JObject or JArray? Please help.
i have tried to create following model class and tried to deserialise but not getting result as expected.
public class PipeLineResponse
{
public string TransactionID { get; set; }
public List<Dictionary<string, string>> fields { get; set; }
}
public class PipeLineResponseObject
{
public List<PipeLineResponse> data { get; set; }
}
How to create that json in that format any DTO or Automapper will work ? Please help me with samples.
The solution that I am laying down here takes the DTO approach. The response from the service is being deserialized to the DTO, which further is being manually mapped to the final ViewModel that we are sending to the client. By no means, this implementation is production-ready and there is scope for improvement, for which I am adding in comments. But this gives a detailed understanding of how we can handle these kind of scenarios. We are making use of Newtonsoft.Json, which can be pulled into your project via the NuGet package manager.
Structure of the DTO
// RootDTO.cs
// This structure is directly based on the response obtained from remote service.
public class Fields
{
[JsonProperty(PropertyName ="Fields.10")]
public string Fields10 { get; set; }
[JsonProperty(PropertyName = "Fields.11")]
public string Fields11 { get; set; }
[JsonProperty(PropertyName = "Fields.12")]
public string Fields12 { get; set; }
}
public class Datum
{
public string Tranid { get; set; }
public Fields fields { get; set; }
}
public class RootDTO
{
[JsonProperty(PropertyName ="data")]
public List<Datum> data { get; set; }
}
Structure of ViewModel
// PipelineResponse.cs
public class FieldsList
{
public string fieldId { get; set; }
public string fieldValue { get; set; }
}
public class ResponseDatum
{
[JsonProperty(PropertyName = "TransactionID")]
public string TransactionID { get; set; }
public List<FieldsList> fieldsList { get; set; }
}
public class PipelineResponse
{
public List<ResponseDatum> data { get; set; }
}
Deserializing the response to the DTO
// ...other code
var responseString = await httpResponseMessage.Content.ReadAsAsync<Object>();
// This is where the DTO object is created. This should be mapped to view model type.
var responseDTO = JsonConvert.DeserializeObject<RootDTO>(responseString);
Mapping the DTO to ViewModel
The mapping from DTO type to ViewModel type needs to be done before sending the response to the client. It is the view model type that is sent to the client. This logic can be placed within a separate helper (ideally, to separate concerns) or any other location as per the practices you are following.
public PipelineResponse ConvertResponseDTOToResponse(RootDTO responseDTO)
{
// FieldId is being hardcoded here. Instead, you can use Reflection to
// fetch the property name, split on '.' and take the item at index 1.
// Notice that DTO properties have "JsonProperty" attributes for this.
try
{
List<ResponseDatum> responseList = new List<ResponseDatum>();
if (responseDTO != null)
{
// Reflection can be used to avoid hardcoding on 'fieldId'
foreach (var item in responseDTO.data)
{
var responseDataObj = new ResponseDatum
{
TransactionID = item.Tranid,
fieldsList = new List<FieldsList>
{
new FieldsList
{
fieldValue = item.fields.Fields10,
fieldId = "10"
},
new FieldsList
{
fieldValue = item.fields.Fields11,
fieldId = "11"
},
new FieldsList
{
fieldValue = item.fields.Fields12,
fieldId = "12"
}
}
};
responseList.Add(responseDataObj);
}
}
// This object is what you return from your controller endpoint finally.
// The serialized response of this object is of the json structure you need
return new PipelineResponse { data = responseList };
}
catch (Exception ex)
{
throw ex;
}
}
So currently this method gets the venuetype and outputs it's name, image and cafeID of that venue.
it's currently being returned as an Array, but I want to return it as an object but wasn't sure how to it's a simple question but I've been staring at it for a while now.
{
public class VenueTypeResponse
{
public string Name { get; set; }
public string ImageUrl { get; set; }
public int id { get; set; }
}
}
public VenueService(EVouchContext context)
{
_context = context;
}
//Gets venuetype and outputs the name, image and cafeID of that venue.
public async Task<List<VenueTypeResponse>> GetVenueType()
{
return await _context.CafeType.Select(s => new VenueTypeResponse()
{
id = s.CafeTypeId,
Name = s.Name,
ImageUrl = s.ImageUrl
}).ToListAsync();
}
I've tried the approach of removing the and returning it as .FirstorDefault but it clearly just returns the first venue type and not all of them. Any suggestions would be great! :)
Response I would like
{
data: [
{
id : 1,
name : "Take aways",
imageUrl : "https://..jpg"
},
{
id : 2,
name : "Desserts",
imageUrl : "https://..jpg"
},
{
...
},
{
...
}
],
meta: {
pageTotal: 1,
pageCurrent: 1
}
}
Response I'm getting
[
{
"name": "Restaurant",
"imageUrl": "https:..",
"id": 1
},
{
"name": "Takeaway",
"imageUrl": "https://...",
"id": 2
},
...
]
You need to create an object that holds your list, something like this:
public class Response
{
[JsonProperty("data")]
public List<VenueTypeResponse> Data { get; set; }
[JsonProperty("meta")]
public ResponseMeta Meta { get; set; }
}
public class ResponseMeta
{
[JsonProperty("pageTotal")]
public int PageTotal { get; set; }
[JsonProperty("pageCurrent")]
public int PageCurrent { get; set; }
}
and then either return this from your method, or wrap the result from this method into this object, before returning it from your endpoint.
I am familiar with JSON.net a bit and can Deserialize the JSON with basic structure (upto one child). I am currently in process of Deserializing the JSON that is returned from Netatmo API. The structure of JSON is complicated for me. Following is the basic structure of the JSON,
_id
place
location
Dynamic Value 1
Dynamic Value2
altitude
timezone
mark
measures
Dynamic Value 1
res
Dynamic Value 1
Dynamic Value 1
Dynamic Value 2
type
Dynamic Value 1
Dynamic Value 2
modules
Dynamic Value 1
Dynamic Value 1 and Dynamic Value 2 represents the values that is changed for each id. The complete JSON is given below,
{
"body": [{
"_id": "70:ee:50:02:b4:8c",
"place": {
"location": [-35.174779762001, -5.8918476117544],
"altitude": 52,
"timezone": "America\/Fortaleza"
},
"mark": 0,
"measures": {
"02:00:00:02:ba:2c": {
"res": {
"1464014579": [16.7, 77]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:02:b4:8c": {
"res": {
"1464014622": [1018.1]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:02:ba:2c"]
}, {
"_id": "70:ee:50:12:40:cc",
"place": {
"location": [-16.074257294385, 11.135715243973],
"altitude": 14,
"timezone": "Africa\/Bissau"
},
"mark": 14,
"measures": {
"02:00:00:06:7b:c8": {
"res": {
"1464015073": [26.6, 78]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:12:40:cc": {
"res": {
"1464015117": [997]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:06:7b:c8"]
}],
"status": "ok",
"time_exec": 0.010364055633545,
"time_server": 1464015560
}
I am confused by looking at the complex structure of this JSON. For single level of JSON I have used this code in the past,
IList<lstJsonAttributes> lstSearchResults = new List<lstJsonAttributes>();
foreach (JToken objResult in objResults) {
lstJsonAttributes objSearchResult = JsonConvert.DeserializeObject<lstJsonAttributes>(objResult.ToString());
lstSearchResults.Add(objSearchResult);
}
But for so many child I have yet to understand how the object class will be created. Any guidance will highly appreciated.
Update:
This is what I have achieved so far.
I have created a main class as below,
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public string mark { get; set; }
public List<string> modules { get; set; }
}
and "Place" class is as follow,
public class PublicData_Place
{
public List<string> location { get; set; }
public string altitude { get; set; }
public string timezone { get; set; }
}
Then I have Deserialized the object in the following code line,
var obj = JsonConvert.DeserializeObject<List<PublicDataClass>>(jsonString);
I can now successfully get all the data except the "measures" which is little bit more complicated.
Using json.net, JSON objects that have arbitrary property names but fixed schemas for their values can be deserialized as a Dictionary<string, T> for an appropriate type T. See Deserialize a Dictionary for details. Thus your "measures" and "res" objects can be modeled as dictionaries.
You also need a root object to encapsulate your List<PublicDataClass>, since your root JSON container is an object like so: { "body": [{ ... }] }.
Thus you can define your classes as follows:
public class RootObject
{
public List<PublicDataClass> body { get; set; }
public string status { get; set; }
public double time_exec { get; set; }
public int time_server { get; set; }
}
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public int mark { get; set; }
public List<string> modules { get; set; }
public Dictionary<string, Measure> measures { get; set; }
}
public class PublicData_Place
{
public List<double> location { get; set; } // Changed from string to double
public double altitude { get; set; } // Changed from string to double
public string timezone { get; set; }
}
public class Measure
{
public Measure()
{
this.Results = new Dictionary<string, List<double>>();
this.Types = new List<string>();
}
[JsonProperty("res")]
public Dictionary<string, List<double>> Results { get; set; }
[JsonProperty("type")]
public List<string> Types { get; set; }
}
Then do
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
var obj = root.body;
I've worked with XML for a few years and my change to JSON structure I've got a little confused too, always that I want to see how an object look like I use this web site jsoneditoronline Just copy and paste your JSON and click on arrow to parse to an object, I hope it helps until you get used to JSON structure.
I am using Unity and the Facebook SDK.
Currently I am retrieving a list of users friends who have the app installed using the graph API:
The data when it is returned looks as such:
{
"data": [
{
"installed": true,
"id": "1292282928282"
},
{
"installed": true,
"id": "29282829292"
}
],
"paging": {
"next": "https://graph.facebook.com/v2.5/105157539862931/friends?fields=installed&format=json&access_token=CAALVPHznNpcBAOnO94HvqUgYKI2kObPZBgR0sqIOMSRO9swZBBTWHb6FjliZCT1KyCmPbnX42xvtngboh3DjFOrixw0pSenwRZA1oXZAHNDdYcGsHNOHjQcZB0f6fsZBQJjhOTttwQu7E5hZBDcAWJVZBGK2AxrZBDZBxLL7I5pjXwwbb12hDytZAiVzUmNzi1Ae2CCvOnL6QCpqzsJT7fWWjXXi&limit=25&offset=25&__after_id=enc_AdB7PJbXYkDSSZAq33AjPXZAeRnlrZBDwjAAILZAg3emHdei0qdRLa2AeD6sRuX6h0OQuPQi8x8bvSHPy0EqIgybYL89"
},
"summary": {
"total_count": 2
}
}
Currently I am trying to figure out how I can extract the "Installed" and id from each object inside of the "data" object.
so far I am doing this:
Dictionary<object,object> friendsList = Json.Deserialize (result.RawResult) as Dictionary<object,object>;
But I am not sure how I can pull out these specific items from the objects.
Does anyone know how I would go about doing this?
You need to have classes that will hold the deserialized data for you. For example create the following classes:
public class Datum
{
public bool installed { get; set; }
public string id { get; set; }
}
public class Paging
{
public string next { get; set; }
}
public class Summary
{
public int total_count { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
public Paging paging { get; set; }
public Summary summary { get; set; }
}
RootObject is the root class so the deserialization code will be:
var deserialized = Json.Deserialize<RootObject>(result.RawResult);
There is one more way to do it without creating classes, by using the dynamic keyword:
static void Main(string[] args)
{
var stringVal = #"{
""data"": [
{
""installed"": true,
""id"": ""1292282928282""
},
{
""installed"": true,
""id"": ""29282829292""
}
],
""paging"": {
""next"": ""https://graph.facebook.com/v2.5/105157539862931/friends? fields=installed&format=json&access_token=CAALVPHznNpcBAOnO94HvqUgYKI2kObPZBgR0sqIOMSRO9swZBBTWHb6FjliZCT1KyCmPbnX42xvtngboh3DjFOrixw0pSenwRZA1oXZAHNDdYcGsHNOHjQcZB0f6fsZBQJjhOTttwQu7E5hZBDcAWJVZBGK2AxrZBDZBxLL7I5pjXwwbb12hDytZAiVzUmNzi1Ae2CCvOnL6QCpqzsJT7fWWjXXi&limit=25&offset=25&__after_id=enc_AdB7PJbXYkDSSZAq33AjPXZAeRnlrZBDwjAAILZAg3emHdei0qdRLa2AeD6sRuX6h0OQuPQi8x8bvSHPy0EqIgybYL89""
},
""summary"": {
""total_count"": 2
}
}";
dynamic x = JsonConvert.DeserializeObject(stringVal);
var data = x.data;
foreach(var d in data)
{
bool installed = d.installed;
long id = d.id;
// todo: use the id and installed
}
Run this in Linqpad and you it will return the installed property.
void Main()
{
string jsonText =
#"{
""data"": [
{
""installed"": true,
""id"": ""1292282928282""
},
{
""installed"": true,
""id"": ""29282829292""
}
],
""paging"": {
""next"": ""https://graph.facebook.com/v2.5/105157539862931/friends?fields=installed&format=json&access_token=CAALVPHznNpcBAOnO94HvqUgYKI2kObPZBgR0sqIOMSRO9swZBBTWHb6FjliZCT1KyCmPbnX42xvtngboh3DjFOrixw0pSenwRZA1oXZAHNDdYcGsHNOHjQcZB0f6fsZBQJjhOTttwQu7E5hZBDcAWJVZBGK2AxrZBDZBxLL7I5pjXwwbb12hDytZAiVzUmNzi1Ae2CCvOnL6QCpqzsJT7fWWjXXi&limit=25&offset=25&__after_id=enc_AdB7PJbXYkDSSZAq33AjPXZAeRnlrZBDwjAAILZAg3emHdei0qdRLa2AeD6sRuX6h0OQuPQi8x8bvSHPy0EqIgybYL89""
},
""summary"": {
""total_count"": 2
}
}";
var x = JsonConvert.DeserializeObject<Response>(jsonText);
//To Get installed
x.data.Select(d => d.installed).Dump();
}
public class Response
{
public Data[] data;
public Paging paging;
public Summary summary;
}
public class Data
{
public bool installed { get; set; }
public string id { get; set; }
}
public class Paging
{
public string next { get; set; }
}
public class Summary
{
public int total_count { get; set;}
}
Consults this example for obtain a friend list using mini json:https://developers.facebook.com/docs/unity/reference/current/Json