Working with Irregular nodes/elements in json response from an API - c#

I have a situation while working with a JSON response from an API. To give a background, I am consuming an API from a source using a REST API using 3.5 .net framework.
Below is the part of the JSON output and I am kind of struggling to use it.
a)
"value": {
"Description": "Total Calculated things",
"2018": "5,820,456 ",
"2019": "2,957,447 "
}
The last 2 elements are dynamic, those are tend to change in API response. I was expecting the format like I have mentioned below, but at this point of given time the source provider is not able to change it as the API is used in many other different programs. And Changing the things in the source API will make other program owners to change.
b)
"value": {
"Description": "Total Calculated EQUITY AND LIABILITIES",
"YearData": [ {
"Data": "5,820,456",
"Year": "2018"
},
{
"Data": "2,957,447 ",
"Year": "2019"
} ]
}
Is there any way to overcome such thing> Any way to convert a to b?
EDIT
#Xerillio , Thanks . How can I achieve the same using below JSON format.
var json = #"
{
""entityData"": [
{
""name"": ""Statement of Comprehensive Income"",
""subattrOutput"": [
{
""name"": ""Sales"",
""subattrOutput"": [],
""value"": {
""Description"": ""Sales "",
""2018"": ""8,704,888 "",
""2019"": ""4,760,717 ""
},
""score"": ""99.5"",
""valuetype"": ""object""
},
{
""name"": ""Cost of goods sold"",
""subattrOutput"": [],
""value"": {
""Description"": ""Cost of sales "",
""2018"": ""(6,791,489) "",
""2019"": ""(3,502,785) ""
},
""score"": ""99.75"",
""valuetype"": ""object""
}
],
""value"": null,
""score"": ""98.63"",
""valuetype"": ""object""
}
]
}";

I wish this was more easy, but i just got it here:
class Program
{
static async Task Main(string[] args)
{
string json1 = #"{""value"": {""Description"": ""Total Calculated things"",""2018"": ""5,820,456 "",""2019"": ""2,957,447 ""}}";
string json2 = #"{""value"": {""Description"": ""Total Calculated EQUITY AND LIABILITIES"",""YearData"": [ {""Data"": ""5,820,456"",""Year"": ""2018""},{""Data"": ""2,957,447 "",""Year"": ""2019""} ]}}";
var obj1 = JsonConvert.DeserializeObject<ObjectResult>(json1);
var obj2 = JsonConvert.DeserializeObject<ObjectResult>(json2);
var res1 = CastObject<Result1>(obj1.Value.ToString());
var res2 = CastObject<Result2>(obj2.Value.ToString());
var invalidRes1 = CastObject<Result1>(obj2.Value.ToString());
var invalidRes2 = CastObject<Result2>(obj1.Value.ToString());
Console.WriteLine(res1);
Console.WriteLine(res2);
}
public static T CastObject<T>(string obj)
{
return !TryCastObject(obj, out T result) ? default : result;
}
public static bool TryCastObject<TOut>(string objToCast, out TOut obj)
{
try
{
obj = JsonConvert.DeserializeObject<TOut>(objToCast);
return true;
}
catch
{
obj = default;
return false;
}
}
}
public class ObjectResult
{
public object Value { get; set; }
}
public class Result1
{
[JsonProperty(PropertyName = "description")] public string Description { get; set; }
[JsonProperty(PropertyName = "2018")] public string _2018 { get; set; }
[JsonProperty(PropertyName = "2019")] public string _2019 { get; set; }
}
public class Result2
{
[JsonProperty(PropertyName = "Description")] public string Description { get; set; }
[JsonProperty(PropertyName = "YearData")] public List<YearData> YearData { get; set; }
}
public class YearData
{
[JsonProperty(PropertyName = "Data")] public string Data { get; set; }
[JsonProperty(PropertyName = "Year")] public string Year { get; set; }
}
It is A LOT of work and sincerely, as there more nodes in the json i think that using JObject is the best option, and you will have to do a deserealization in more than 1 step :(

Depending on how large the JSON structure is you could deserialize it into a Dictionary and manually map it to the proper format:
var json = #"
{
""value"": {
""Description"": ""Total Calculated things"",
""2018"": ""5,820,456 "",
""2019"": ""2,957,447 ""
}
}";
var badObj = JsonSerializer.Deserialize<BadFormat>(json);
var result = new WrapperType
{
Value = new ProperlyFormattedType()
};
foreach (var pair in badObj.Value)
{
if (pair.Key == "Description")
{
result.Value.Description = pair.Value;
}
else if (int.TryParse(pair.Key, out int _))
{
result.Value.YearData
.Add(new DatedValues
{
Year = pair.Key,
Data = pair.Value
});
}
}
// Data models...
public class BadFormat
{
[JsonPropertyName("value")]
public Dictionary<string, string> Value { get; set; }
}
public class WrapperType
{
public ProperlyFormattedType Value { get; set; }
}
public class ProperlyFormattedType
{
public string Description { get; set; }
public List<DatedValues> YearData { get; set; } = new List<DatedValues>();
}
public class DatedValues
{
public string Year { get; set; }
public string Data { get; set; }
}
See an example fiddle here.

Related

Add value in json in each records

I have json format as below. In that I have multiple records coming, check below json.
{
"metadata":{
"TotalCount":11,
"CurrentPageNumber":1,
},
"records":[
{
"offerId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"isContract":true,
"transportRouteId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"transportOrderId":"SEZYMY-210720-010097",
"schedule":null,
},
]
}
Now I want to add new value in each this records array, so how can I do that.
I want to add this value : ("carrierExpiredDate", (carrierExpiredDate.ComplianceExpiryDate.Value).Date);
So this new json should look like this.
{
"metadata":{
"TotalCount":11,
"CurrentPageNumber":1,
},
"records":[
{
"offerId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"isContract":true,
"transportRouteId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"transportOrderId":"SEZYMY-210720-010097",
"schedule":null,
"carrierExpiredDate": (carrierExpiredDate.ComplianceExpiryDate.Value).Date)
},
]
}
var json =
#"{
"metadata":{
"TotalCount":11,
"CurrentPageNumber":1,
},
"records":[
{
"offerId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"isContract":true,
"transportRouteId":"e1b75d86-67b1-4557-a381-5474383da3fb",
"transportOrderId":"SEZYMY-210720-010097",
"schedule":null
},
]
}";
var jObject = JObject.Parse(json);
var jList=jObject["records"].Children().ToList();
foreach(var jtoken in jList)
{
jtoken["carrierExpiredDat"] = (carrierExpiredDate.ComplianceExpiryDate.Value).Date));
}
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jObject, Newtonsoft.Json.Formatting.Indented);
Try this. The code was tested using Visual Studio and Postman
.....
var expDate=DateTime.Now;
var json = await response.Content.ReadAsStringAsync()
var deserializedJson = JsonConvert.DeserializeObject<TransportRoot>(json);
deserializedJson.Records.ForEach(i=> i.carrierExpiredDate=expDate);
var newJson= JsonConvert.SerializeObject(deserializedJson);
classes
public class Metadata
{
public int TotalCount { get; set; }
public int CurrentPageNumber { get; set; }
}
public class Record
{
public string offerId { get; set; }
public bool isContract { get; set; }
public string transportRouteId { get; set; }
public string transportOrderId { get; set; }
public object schedule { get; set; },
public object carrierExpiredDate { get; set; }
}
public class TransportRoot
{
public Metadata Metadata { get; set; }
public List<Record> Records { get; set; }
}
if you have a problem with a camel case json, I highly recommend to change your startup
services.AddControllers()
// or services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver());

How can i search a json response to see if a value exists using linq?

I have the following json response
{
"Id": "1234",
"Name": "Test",
"Orders": [
{
"OrderId": "87654",
"OrderDetails": {
"OrdId": "1234",
"Name": "Desk"
}
},
{
"OrderId": "54213",
"OrderDetails": {
"OrdId": "4321",
"Name": "Table"
}
}
]
}
I want to search the list of orders to see if there is an OrderId of 87654.
I can do with an array , but how can I do it with Linq ?
You can deserialize the json string to a JObject using Newtonsoft.Json and then loop through the orders to get the OrderIDs.
var obj = JObject.Parse(json);
foreach(var order in obj["Orders"])
{
Console.WriteLine(order["OrderId"]);
}
or you can use the Where clause.
var myOrder = obj["Orders"].Where(x => x["OrderId"].ToString().Equals("87654")).FirstOrDefault();
Then you can print any property of that order,
Console.WriteLine(myOrder["OrderDetails"]["Name"].ToString());
// Prints: Desk
Alternatively, you can: also use classes to deserialize the json you have and query the orders.
public class OrderDetails
{
public string OrdId { get; set; }
public string Name { get; set; }
}
public class Order
{
public string OrderId { get; set; }
public OrderDetails OrderDetails { get; set; }
}
public class RootObject
{
public string Id { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
public static void Main(string[] args)
{
string json = File.ReadAllText(#"C:\temp\json.txt");
var obj = JsonConvert.DeserializeObject<RootObject>(json);
var myOrder = obj.Orders.FirstOrDefault(x => x.OrderId.Equals("87654"));
if (myOrder != null)
{
Console.WriteLine(myOrder.OrderDetails.Name);
}
}
Demo on dotnet fiddle
You can use Newtonsoft to achieve it
var jsonData = "{ 'Id': '1234', 'Name': 'Test', 'Orders': [ {'OrderId': '87654', 'OrderDetails': { 'OrdId': '1234', 'Name': 'Desk' } }, { 'OrderId': '54213', 'OrderDetails': { 'OrdId': '4321','Name': 'Table' }}]}";
var desirializedData = JsonConvert.DeserializeObject<MyObject>(jsonData);
var result = desirializedData.Orders.Where(p => p.OrderId == 87654);
foreach(var master in result)
{
Console.WriteLine(master.OrderId + " " + master.OrderDetails.Name);
}

Returning Array of response from Web API C#

I am trying to create a web API which calls the other service and returns a array of response. The called service returns the response. I am able to get the individual item from the called service. But not sure how to build array of items and return as response from the API I am creating.
The JSON returned from the service looks like
{
"cr_response": {
"details": [{
"name": "Req",
"fields": [{
"value": "Prj0\r\nPrj1",
"name": "Project"
},
{
"value": "October 13, 2017 14:18",
"name": "Submitted"
},
{
"value": "John",
"name": "Rec Name"
}
]
}],
"cr_metadata": {}
}
}
And the POCO class looks like
public class Field
{
public string value { get; set; }
public string name { get; set; }
}
public class Detail
{
public string name { get; set; }
public List<Field> fields { get; set; }
}
public class CrMetadata
{
}
public class CrResponse
{
public List<Detail> details { get; set; }
public CrMetadata cr_metadata { get; set; }
}
public class RootObject
{
public CrResponse cr_response { get; set; }
}
Below is the code for calling the service and retrieving the response from the services
var response = await iLab_client.GetAsync(uri);
var datafile = await response.Content.ReadAsStringAsync();
var returnDataObj = JsonConvert.DeserializeObject<DTO.RootObject>(datafile);
foreach (var form in returnDataObj.cr_response.details)
{
name_response = form.name;
return Ok(name_response);
}
Here I can access the name from the details but not sure how can I access the all the name and value from the fields and construct it in a array. And send it as a JSON response.
I tried like
foreach (var form in returnDataObj.cr_response.details)
{
var id_response = form.fields;
return Ok(id_response);
}
But it throws error like
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content
type 'application/xml; charset=utf-8'.
</ExceptionMessage>
System.InvalidOperationException
To return array from Web API you need to fill your array and return it outside foreach loop:
var list = new List<string>();
foreach (...){
var name = ...
list.Add(name);
}
return Ok(list.ToArray()); // or just return Ok(list);
This is how to deserialize JSON to POCO and get the list of the names:
[TestMethod]
public void TestJsonToPocoAndGetNames()
{
const string Json = #"
{
""cr_response"": {
""details"": [{
""name"": ""Req"",
""fields"": [{
""value"": ""Prj0\r\nPrj1"",
""name"": ""Project""
},
{
""value"": ""October 13, 2017 14:18"",
""name"": ""Submitted""
},
{
""value"": ""John"",
""name"": ""Rec Name""
}
]
}],
""cr_metadata"": {}
}
}
";
var settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
var response = JsonConvert.DeserializeObject<RootJsonObject>(Json, settings);
var names = new List<string>();
foreach (var detail in response.CrResponse.Details)
{
names.Add(detail.Name);
foreach (var field in detail.Fields)
{
names.Add(field.Name);
}
}
Assert.AreEqual(
"Req, Project, Submitted, Rec Name",
string.Join(", ", names.ToArray()));
}
POCO classes:
public class RootJsonObject
{
[JsonProperty("cr_response")]
public CrResponse CrResponse { get; set; }
}
public class CrResponse
{
[JsonProperty("cr_metadata")]
public CrMetadata CrMetadata { get; set; }
[JsonProperty("details")]
public Detail[] Details { get; set; }
}
public class CrMetadata
{
}
public class Detail
{
[JsonProperty("fields")]
public Field[] Fields { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class Field
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}

How to get an item value of json using C#?

How to get an item value of json using C#?
json:
[{
ID: '6512',
fd: [{
titie: 'Graph-01',
type: 'graph',
views: {
graph: {
show: true,
state: {
group: 'DivisionName',
series: ['FieldWeight', 'FactoryWeight', 'Variance'],
graphType: 'lines-and-points'
}
}
}
}, {
titie: 'Graph-02',
type: 'Graph',
views: {
graph: {
show: true,
state: {
group: 'DivisionName',
series: ['FieldWeight', 'FactoryWeight', 'Variance'],
graphType: 'lines-and-points'
}
}
}
}]
}, {
ID: '6506',
fd: [{
titie: 'Map-01',
type: 'map',
views: {
map: {
show: true,
state: {
kpiField: 'P_BudgetAmount',
kpiSlabs: [{
id: 'P_BudgetAmount',
hues: ['#0fff03', '#eb0707'],
scales: '10'
}]
}
}
}
}]
}]
Above mentioned one is json, Here titie value will be get in a list
please help me...
My code is:
string dashletsConfigPath = Url.Content("~/Content/Dashlets/Dashlets.json");
string jArray = System.IO.File.ReadAllText(Server.MapPath(dashletsConfigPath));
List<string> lists = new List<string>();
JArray list = JArray.Parse(jArray);
var ll = list.Select(j => j["fd"]).ToList();
Here json will be converted in to JArray then
li got fd details then we got tite details on a list
If you just want a List<string> of the "titie" (sic) property values, this should work, using SelectMany:
List<string> result = list.SelectMany(
obj => obj["fd"]
.Select(inner => inner["titie"].Value<string>()))
.ToList()
This assumes that the JSON you posted is made valid by quoting property names.
I would recommend creating a class for your objects and use a DataContractSerializer to deserialize the JSON string.
[DataContract]
public class Container
{
[DataMember(Name="ID")]
public string ID { get; set; }
[DataMember(Name="fd")]
public Graph[] fd { get; set; }
}
[DataContract]
public class Graph
{
[DataMember(Name="title")]
public string Title { get; set; }
[DataMember(Name="type")]
public string Type { get; set; }
}
etc.
This will give you strongly typed classes around your JSON.
I'm not sure how you intend to use the data but you can collect all the titie values from your objects like this:
var arr = JArray.Parse(json);
var query =
from JObject obj in arr
from JObject fd in obj["fd"]
select new
{
Id = (string)obj["ID"],
Titie = (string)fd["titie"],
};
You can use json.net to deserialize json string like this:
public class Item
{
public string ID { get; set; }
public List<FD> fd { get; set; }
}
public class FD
{
public string titie { get; set; }
public string type { get; set; }
public Views views { get; set; }
}
public class Views
{
public Graph graph { get; set; }
}
public class Graph
{
public bool show { get; set; }
public State state { get; set; }
}
public class State
{
public string group { get; set; }
public string[] series { get; set; }
public string graphType { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = #"..."; //your json string
var Items = JsonConvert.DeserializeObject<List<Item>>(json);
List<string> tities = new List<string>();
foreach (var Item in Items)
{
foreach (var fd in Item.fd)
{
tities.Add(fd.titie);
}
}
}
}
First thing is your json format invalid. get the valid json below.
[{
"ID": "6512",
"fd": [{
"titie": "Graph-01",
"type": "graph",
"views": {
"graph": {
"show": true,
"state": {
"group": "DivisionName",
"series": ["FieldWeight", "FactoryWeight", "Variance"],
"graphType": "lines-and-points"
}
}
}
}, {
"titie": "Graph-02",
"type": "Graph",
"views": {
"graph": {
"show": true,
"state": {
"group": "DivisionName",
"series": ["FieldWeight", "FactoryWeight", "Variance"],
"graphType": "lines-and-points"
}
}
}
}]
}, {
"ID": "6506",
"fd": [{
"titie": "Map-01",
"type": "map",
"views": {
"map": {
"show": true,
"state": {
"kpiField": "P_BudgetAmount",
"kpiSlabs": [{
"id": "P_BudgetAmount",
"hues": ["#0fff03", "#eb0707"],
"scales": "10"
}]
}
}
}
}]
}]
And if you want to read items as separate strings use following code.
JArray jObject = JArray.Parse(json);
var ll = jObject.ToList();
You can use Newtonsoft Json Library.
Deserialize your json string with the model objects below
public class JsonWrapper
{
public string ID { get; set; }
public List<Fd> fd { get; set; }
}
public class Fd
{
public string titie { get; set; }
public string type { get; set; }
public Views views { get; set; }
}
public class Views
{
public Graph graph { get; set; }
}
public class Graph
{
public bool show { get; set; }
public State state { get; set; }
}
public class State
{
public string group { get; set; }
public List<string> series { get; set; }
public string graphType { get; set; }
}
Declare on object of JsonWrapper class and deserialize the json string to it.
JsonWrapper jsonWrapper = new JsonWrapper();
jsonWrapper = (JsonWrapper)JsonConvert.DeserializeObject(jsonString, jsonWrapper.getType());
Then you can access all the lists and properties from the jsonWrapper object.

Read JSON string as key value

I have following json:
{
"serverTime": "2013-08-12 02:45:55,558",
"data": [
{
"key1": 1,
"key2": {},
"key3": {
"key4": [
""
],
"key5": "test2"
},
"key7": 0
},
{
"key8": 1,
"key9": {},
"key10": {
"key4": [
""
],
"key9": "test2"
},
"key11": 0
}
]
}
I want to get values as key value pair. Something like:
jsonObject[data][0]
should give first item of the data array.
I am using JSONFx.net. But it gives strongly typed objects. I do not want that.
Is there any way to parse JSON as key value as I mentioned earlier?
Thanks
Try this:
using System;
using System.IO;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
var json = File.ReadAllText("input.txt");
var a = new { serverTime = "", data = new object[] { } };
var c = new JsonSerializer();
dynamic jsonObject = c.Deserialize(new StringReader(json), a.GetType());
Console.WriteLine(jsonObject.data[0]);
}
}
If you're not averse to using Json.NET, you can do this:
var jsonString = #"
{
""serverTime"": ""2013-08-12 02:45:55,558"",
""data"": [
{
""key1"": 1,
""key2"": {},
""key3"": {
""key4"": [
""""
],
""key5"": ""test2""
},
""key7"": 0
},
{
""key8"": 1,
""key9"": {},
""key10"": {
""key4"": [
""""
],
""key9"": ""test2""
},
""key11"": 0
}
]
}";
var jsonResult = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(jsonString);
var firstItem = jsonResult["data"][0];
firstItem would be an array of the first item in the data array:
Hope this helps.
First create classes to parse string
public class Key2
{
}
public class Key3
{
public List<string> key4 { get; set; }
public string key5 { get; set; }
}
public class Key9
{
}
public class Key10
{
public List<string> key4 { get; set; }
public string key9 { get; set; }
}
public class Datum
{
public int key1 { get; set; }
public Key2 key2 { get; set; }
public Key3 key3 { get; set; }
public int key7 { get; set; }
public int? key8 { get; set; }
public Key9 key9 { get; set; }
public Key10 key10 { get; set; }
public int? key11 { get; set; }
}
public class RootObject
{
public string serverTime { get; set; }
public List<Datum> data { get; set; }
}
add reference of Newtonsoft.Json.dll
RootObject obj = JsonConvert.DeserializeObject<RootObject>(jsonData);
then you can access values .
If you want to do this without third party libraries then do:
I would use the following code:
var deserializer = new JavaScriptSerializer();
var someObject = deserializer.DeserializeObject(json);
string serverTime = someObject["serverTime"].ToString();
Dictionary<string, int> data = someObject["data"] as Dictionary<string, int>;
Give it a go.
Edit: You may need to change the last line to:
Dictionary<string, int?> data = someObject["data"] as Dictionary<string, int?>;

Categories

Resources