I am using a thirdparty API and the Json response that I receive back is as below.
Usually, using something like
Newtonsoft.Json.JsonConvert.DeserializeObject<MyModel>(response);
I can easily create a .Net model. However, I am struggling on how to formulate the below. I've tried KeyValuePairs, strings, modifying the actual Json but cannot seem to get any joy.
What am I missing?
{
"1": [
{
"qty": 1,
"discount": "flat",
"price": 71.68
}
],
"2": [
{
"qty": 1,
"discount": "flat",
"price": 62.75
}
],
"3": [
{
"qty": 1,
"discount": "flat",
"price": 77.28
}
],
"4": [
{
"qty": 1,
"discount": "flat",
"price": 82.88
}
],
"5": [
{
"qty": 1,
"discount": "flat",
"price": 67.84
}
]
}
Now, what is throwing me is that the numbers(1,2,3,4,5) are Identifiers so will not stay constant and could change each time you receive the response.
I think Newtonsoft can do this for you.
string json = #"{
'Email': 'james#example.com',
'Active': true,
'CreatedDate': '2013-01-20T00:00:00Z',
'Roles': [
'User',
'Admin'
]
}";
var jsonReturn = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>( json );
Console.WriteLine( jsonReturn.Email );
Based on this link:
https://www.newtonsoft.com/json/help/html/DeserializeObject.htm
This is the most basic explanation. Use a foreach to iterate over de nodes
Using #Liam's suggestion of JObject I have come up with this working solution
public class MyObject
{
public int id { get; set; }
public int qty { get; set; }
public string discount { get; set; }
public decimal price { get; set; }
}
and then after retrieving the JSON response...
var jsonObj = JsonConvert.DeserializeObject<JObject>(response);
List<MyObject> myObjects = new List<MyObject>();
foreach (var item in jsonObj.AsJEnumerable())
{
var csp = JsonConvert.DeserializeObject<List<MyObject>>(item.First.ToString());
csp.ForEach(a => { a.product_id = Convert.ToInt32(item.Path); });
myObjects.AddRange(csp);
}
Related
I've a JSON object containing an array like this:
{
"CustRecord": [
{
"ID": "40274",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
},
{
"ID": "40275",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
}
]
}
and I want to remove the property name "CustRecord" from JSON to create the following output using C#.
How can I achieve this?
[
{
"ID": "40274",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
},
{
"ID": "40275",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
}
]
In .NET 6 you can use the new "System.Text.Json.Nodes" namespace. It introduced JsonObject and JsonNode. You can do the following:
JsonNode original = JsonObject.Parse(jsonString);
string newJson = original["CustRecord"].ToJsonString();
If you want the serialized result to be indented (pretty) Json, then you can pass JsonSerializerOptions to ToJsonString():
string newJson = original["CustRecord"].ToJsonString(new JsonSerializerOptions
{
WriteIndented = true
});
try this
var newJson=JObject.Parse(json)["CustRecord"].ToString();
or the most efficient way
json=json.Substring(0,json.Length-1).Substring(json.IndexOf(":")+1);
result
[
{
"ID": "40274",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
},
{
"ID": "40275",
"Currency": "USD",
"CustomerNumber": "123456",
"CustomerName": "contoso"
}
]
but if you need to deserialize json, not just parse , the best way would be
var customerRecord =JObject.Parse(json)["CustRecord"].ToObject<CustomerRecord>();
class
public class CustomerRecord
{
public string ID { get; set; }
public string Currency { get; set; }
public string CustomerNumber { get; set; }
public string CustomerName { get; set; }
}
I need to extract data from mongodb, but this data differs in coordinates, I can create a base-sub class structure and POST it to mongodb, but the coordinates do not come in the GET operation.
public class Geometry
{
public string type { get; set; }
}
public class GeoPoly:Geometry
{
public double[][][] coordinates { get; set; }
}
public class GeoMultipoly : Geometry
{
public double[][][][] coordinates { get; set; }
}
how can I do that
Should the serialization convention change and how should it change
Is the base-sub class structure suitable for this problem?
database entries:
{
"type": "Polygon",
"coordinates": [
[
[
[
51.263632,
60.962938
],
[
30.884274,
20.065517
],
[
68.832044,
14.362602
],
[
51.263632,
60.962938
]
]
]
]
},
{
"type": "MultiPolygon",
"coordinates": [
[
[
[
43.182162,
64.042209
],
[
14.721334,
22.358269
],
[
51.263632,
17.738761
],
[
43.182162,
64.042209
]
]
],
[
[
[
55.831419,
51.446822
],
[
65.66973,
20.065517
],
[
97.64424,
37.509124
],
[
55.831419,
51.446822
]
]
]
]
}
I am not sure is the best idea,
but newtonsoft json.net support serialize and deserialize with $type.
The item will be saved in DB with it's full class identifier.
You can check here
An example:
// {
// "$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests",
// "FullName": "Steve Stockholder",
// "Businesses": {
// "$type": "System.Collections.Generic.List`1[[Newtonsoft.Json.Samples.Business, Newtonsoft.Json.Tests]], mscorlib",
// "$values": [
// {
// "$type": "Newtonsoft.Json.Samples.Hotel, Newtonsoft.Json.Tests",
// "Stars": 4,
// "Name": "Hudson Hotel"
// }
// ]
// }
// }
To use it check newtonsoft documentation here.
Example of usage:
Stockholder stockholder = new Stockholder
{
FullName = "Steve Stockholder",
Businesses = new List<Business>
{
new Hotel
{
Name = "Hudson Hotel",
Stars = 4
}
}
};
string jsonTypeNameAll = JsonConvert.SerializeObject(stockholder, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
For this JSON right class to do is:
public class Rootobject
{
public string type { get; set; }
public float[][][][] coordinates { get; set; }
}
For GeoPoly and GeoMultipoly there practical the same. You can procesig this in two steps:
Get the list od Rootobject (List)
switch(g.type)
{
case "GeoPoly":
result.Add(new GeoPoly
{
type = g.type;
coordinates = g.coordinates
});
break;
case "GeoMultipoly":
result.Add(new GeoMultipoly
{
type = g.type;
coordinates = g.coordinates
});
break;
default:
continue;
}
At the end the result list will have a list of Geometry types in right type.
I am new to JSON and trying to develop a comparison table with data coming from 2 different JSON files as follows.
Json File 1
"data":[
{
"EffectiveDate": "2017-04-01T00:00:00Z",
"IncludedQuantity": 0,
"Category": "VM",
"Id": "d0bf9053",
"Name": "Element1",
"Rates": {
"0": 0.04
},
"Region": "US",
"Status": "Active",
"SubCategory": "S1",
"Tags": [],
"Unit": "Hours"
},
{
"EffectiveDate": "2017-02-01T00:00:00Z",
"IncludedQuantity": 0,
"Category": "DS",
"Id": "8b7672d4",
"Name": "Element2",
"Rates": {
"0": 4.0177
},
"Region": "UK",
"Status": "Active",
"SubCategory": "S2",
"Tags": [],
"Unit": "Days"
}]
Json File 2
"data":{
"d0bf9053":{
"EffectiveDate": "2017-04-01T00:00:00Z",
"IncludedQuantity": 0,
"Category": "VM",
"Id": "d0bf9053",
"Attributes":{
"Name": "Element1",
"Rates": {
"0": 5
},
"Region": "US",
"Status": "Active",
"SubCategory": "S1",
"Tags": [],
"Unit": "Hours"
}
},
"8b7672d4":{
"EffectiveDate": "2017-02-01T00:00:00Z",
"IncludedQuantity": 0,
"Category": "DS",
"Id": "8b7672d4",
"Attributes":{
"Name": "Element2",
"Rates": {
"0": 1
},
"Region": "UK",
"Status": "Active",
"SubCategory": "S2",
"Tags": [],
"Unit": "Days"
}
}}
Now I have to read this data and merge it to create a comparison based on rates and categories. I have created a Dot.Net Console Application and trying to use SQL Server to store the information. Now I am able to read JSON File 1 easily. But I am facing difficulty in storing values from JSON File 2. How do I solve this or am I wrong somewhere.
Thanks in advance.
The problem here is that you have dynamic property names in the second JSON file (Json File 2) and you are probably having trouble deserializing that JSON into a .Net Class, right?
Here are some examples that you can use to deserialize both Json1 and Json2 Types:
public class dataJson1
{
public List<Detail> data { get; set; }
}
public class dataJson2
{
public Dictionary<string, Detail> data { get; set; }
}
public class Detail
{
public DateTime EffectiveDate { get; set; }
public int IncludedQuantity { get; set; }
public string Category { get; set; }
//add the rest of the props here
}
That should get you started, once it's deserialized into those Objects, comparing them should be trivial.
I'm calling the JIRA Rest API to recieve a list of Worklog Objects.
The JSON I recieve looks like.
{
"startAt": 0,
"maxResults": 1,
"total": 1,
"worklogs": [
{
"self": "http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000",
"author": {
"self": "http://www.example.com/jira/rest/api/2/user?username=fred",
"name": "fred",
"displayName": "Fred F. User",
"active": false
},
"updateAuthor": {
"self": "http://www.example.com/jira/rest/api/2/user?username=fred",
"name": "fred",
"displayName": "Fred F. User",
"active": false
},
"comment": "I did some work here.",
"visibility": {
"type": "group",
"value": "jira-developers"
},
"started": "2015-08-25T07:43:10.086+0000",
"timeSpent": "3h 20m",
"timeSpentSeconds": 12000,
"id": "100028"
}
]
}
As I said, I want to put it in a list.
var json = client.MakeRequest("", password, user);
List<Worklog> myList = JsonConvert.DeserializeObject<List<Worklog>>(json);
It doesn't work, because of
"startAt": 0,
"maxResults": 1,
"total": 1,
How can I make the deserializer ignore those properties?
Thanks for your help!
Either create a "RootObject" class that does contain the properties:
public class RootObject
{
public int startAt { get; set; }
public int maxResults { get; set; }
public int total { get; set; }
public List<Worklog> worklogs { get; set; }
}
And deserialize into that:
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
// access rootObject.worklogs
Or step into the parsed JSON and deserialize from there:
JObject o = JObject.Parse(json);
JToken worklogsJson = o.SelectToken("worklogs");
var worklogs = worklogsJson.ToObject<List<Worklog>>();
I have a Json response that I receive from an API call. It has several nested levels as show below (this is a snippet):
"Items": [
{
"Result": {
"Id": "191e24b8-887d-e111-96ec-000c29128cee",
"Name": "Name",
"StartDate": "2012-04-03T00:00:00+01:00",
"EndDate": null,
"Status": {
"Name": "Active",
"Value": 5
},
"Client": {
"Id": "35ea10da-b8d5-4ef8-bf23-c829ae90fe60",
"Name": "client Name",
"AdditionalItems": {}
},
"ServiceAgreement": {
"Id": "65216699-a409-44b0-8294-0e995eb05d9d",
"Name": "Name",
"AdditionalItems": {
"ScheduleBased": true,
"PayFrequency": {
"Id": "981acb72-8291-de11-98fa-005056c00008",
"Name": "Weekly",
"AdditionalItems": {}
},
"PayCycle": [
{
"Name": "Schedule Based",
"ScheduleBased": true,
"SelfBilling": false,
"Id": "a8a2ecc4-ff79-46da-a135-743b57808ec3",
"CreatedOn": "2011-09-16T23:32:19+01:00",
"CreatedBy": "System Administrator",
"ModifiedOn": "2011-09-16T23:32:19+01:00",
"ModifiedBy": "System Administrator",
"Archived": false
}
]
}
},
}
]
...
What I want to do is retreive the data from the PayCycle node using Linq. I can for example get the items with a value of true using Result.ServiceAgreement.AdditionalItems.SchedultedBased using the following Linq in the Controller:
var result = from p in data["Data"]["Items"].Children()
where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true
select new
{
Name = (string)p["Result"]["Client"]["Name"],
Id = (string)p["Result"]["Client"]["Id"]
};
Now I need to get Result.ServiceAgreement.AdditionalItems.Paycycle.ScheduleBased and SelfBilling properties. How do I do this if PayCycle is also an array, how do I get the children as I did with Data.Items in the Linq above so that I can have the where clause filter on both these items?
You can deserialize the JSON into a dynamic object, and then use Linq to Objects:
[TestMethod]
public void TestMethod1()
{
const string json = #"""Items"": [
{
""Result"": {
""Id"": ""191e24b8-887d-e111-96ec-000c29128cee"",
""Name"": ""Name"",
""StartDate"": ""2012-04-03T00:00:00+01:00"",
""EndDate"": null,
""Status"": {
""Name"": ""Active"",
""Value"": 5
},
""Client"": {
""Id"": ""35ea10da-b8d5-4ef8-bf23-c829ae90fe60"",
""Name"": ""client Name"",
""AdditionalItems"": {}
},
""ServiceAgreement"": {
""Id"": ""65216699-a409-44b0-8294-0e995eb05d9d"",
""Name"": ""Name"",
""AdditionalItems"": {
""ScheduleBased"": true,
""PayFrequency"": {
""Id"": ""981acb72-8291-de11-98fa-005056c00008"",
""Name"": ""Weekly"",
""AdditionalItems"": {}
},
""PayCycle"": [
{
""Name"": ""Schedule Based"",
""ScheduleBased"": true,
""SelfBilling"": false,
""Id"": ""a8a2ecc4-ff79-46da-a135-743b57808ec3"",
""CreatedOn"": ""2011-09-16T23:32:19+01:00"",
""CreatedBy"": ""System Administrator"",
""ModifiedOn"": ""2011-09-16T23:32:19+01:00"",
""ModifiedBy"": ""System Administrator"",
""Archived"": false
}
]
}
}
}
}
]";
dynamic data = System.Web.Helpers.Json.Decode("{" + json + "}");
var result = from i in (IEnumerable<dynamic>)data.Items
where i.Result.ServiceAgreement.AdditionalItems.ScheduleBased == true
select new
{
i.Result.Client.Name,
i.Result.Client.Id
};
Assert.AreEqual(1, result.Count());
Assert.AreEqual("client Name", result.First().Name);
Assert.AreEqual("35ea10da-b8d5-4ef8-bf23-c829ae90fe60", result.First().Id);
}
Note that I had to add brackets { and } around your example json string, or else the .NET json parser doesn't like it.
To start off, I'm not familiar with writing LINQ/LAMBDA using this format ["some"]["thing"].
My first step would be to create some classes/objects to house the data in to ease creating any code afterwards.
e.g.
public class Result
{
public Guid Id { get; set; }
public string Name { get; set; },
public DateTime StartDate { get; set; }
//you get the idea
}
But possibly try the following?
var result = from p in data["Data"]["Items"].Children()
where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true
&& (p["Result"]["ServiceAgreement"]["AdditionalItems"]["PayCycle"]).Where(o => o.["ScheduleBased"] == true)
select new
{
Name = (string)p["Result"]["Client"]["Name"],
Id = (string)p["Result"]["Client"]["Id"]
};