I want to parse below JSON in ASP.NET.
{
"destination_addresses": [
"Address 1"
],
"origin_addresses": [
"Address 2"
],
"rows": [
{
"elements": [
{
"distance": {
"text": "15.7 km",
"value": 15664
},
"duration": {
"text": "17 mins",
"value": 1036
},
"status": "OK"
}
]
}
],
"status": "OK"
}
I want to retrieve the text and value from a distance token. I was able to reach till elements.
var objectjson = JObject.Parse(response.Content);
dynamic dynJson = JsonConvert.DeserializeObject(objectjson["rows"].ToString());
var elements = dynJson[0].ToString();
var firstElement = JObject.Parse(elements);
How to parse the json further to reach to the distance token and then text and value?
Create a class like:
public class Distance {
public string text { get; set; }
public int value { get; set; }
}
public class Duration {
public string text { get; set; }
public int value { get; set; }
}
public class Element {
public Distance distance { get; set; }
public Duration duration { get; set; }
public string status { get; set; }
}
public class Row {
public List<Element> elements { get; set; }
}
public class Root {
public List<string> destination_addresses { get; set; }
public List<string> origin_addresses { get; set; }
public List<Row> rows { get; set; }
public string status { get; set; }
}
then, you can convert on it and construct your logic easylly
var myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
Sites references:
Json2Csharp
NewtonSoft
If you don't want to design a data model corresponding to your JSON, you can access nested JToken values using its item indexer:
var distance = objectjson["rows"]?[0]?["elements"]?[0]?["distance"];
var text = (string)distance?["text"];
var value = (decimal?)distance?["value"]; // Or int or double, if you prefer.
You can also use SelectToken() to access nested values:
var distance = objectjson.SelectToken("rows[0].elements[0].distance");
Notes:
There is no need to reformat and reparse the JSON simply to access nested data. I.e. JsonConvert.DeserializeObject(objectjson["rows"].ToString()) is superfluous and will harm performance.
I am using the null-conditional operator ?[] to access nested tokens in case any of the intermediate properties are missing. If you are sure the properties are never missing or would prefer to throw an exception, you can do
var distance = objectjson["rows"][0]["elements"][0]["distance"];
Demo fiddle here.
Take this sample json and:
Go to visual studio
In the menu -> Edit -> Paste Special -> Paste JSON and Classes
VS will generate the classes for you. It will generate the root type as Root, rename it to whatever you want or leave it as Root. Then you can simply deserialise your string into that class.
var rootObject = JsonConvert.DeserializeObject<Root>(response.Content);
// Simply use rootObject to access any property
var firstElement = rootObject.rows[0].elements[0];
// firstElement.distance.text
// firstElement.distance.value
// firstElement.duration.text
// firstElement.duration.value
// firstElement.status
You can traverse the data this way:
' strBuf = your json string
Dim jOb As JObject = JObject.Parse(strBuf)
Dim MyDistance As JToken = jOb.SelectToken("rows[0].elements[0]")
After above, then
Text = MyDistance.SelectToken("distance.text").ToString
value = MyDistance.SelectToken("distance.value").ToString
Status = MyDistance.SelectToken("status").ToString
The above will get you the 3 values. Note that each of the rows are repeating data, so it not clear if you have one string, and with to pull the values, or pull multiple values? If you need to pull repeating data, then above would change.
The above is vb, but it quite much the same in c#.
Related
I've simplified the code (below) but I cannot figure out why the Result.Data property is not getting filled; it is always null. I've used jsonlint.com to validate the JSON (both this small sample and the full content). I built a separate project (using How to Deserialize a Complex JSON Object in C# .NET) and it successfully serializes the complex object listed there. But I cannot get this one to work and I'm stumped.
using System.Text.Json;
namespace JsonTest2;
public class Result
{
public string? Total { get; set; }
public string? Limit { get; set; }
public string? Start { get; set; }
protected List<Park>? Data { get; set; }
}
public class Park
{
public string? Id { get; set; }
}
internal class Program
{
var basepath = AppDomain.CurrentDomain.BaseDirectory;
var filepath = basepath.Split("\\bin")[0];
var filename = #$"{filepath}\NPS_response_small.json";
var jsonstr = File.ReadAllText(filename);
var response = JsonSerializer.Deserialize<Result>(jsonstr, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
This is the content of "NPS_response_small.json":
{
"total": "468",
"limit": "50",
"start": "0",
"data": [
{
"id": "77E0D7F0-1942-494A-ACE2-9004D2BDC59E"
},
{
"id": "6DA17C86-088E-4B4D-B862-7C1BD5CF236B"
},
{
"id": "E4C7784E-66A0-4D44-87D0-3E072F5FEF43"
}
]
}
you have to chanbe a protected attribute of property Data to a public. Json deserializer doesnt have any acces to this property
public List<Park>? Data { get; set; }
it would be much easier to use Newtonsoft.Json, but if you need protected for some reason, you can try this ( but I am not sure that it is a full replacement)
public List<Park>? Data { protected get; init ; }
[System.Text.Json.Serialization.JsonConstructor]
public Result (List<Park>? Data, string? Total, string? Limit, string? Start)
{
this.Data=Data;
this.Total=Total;
this.Limit=Limit;
this.Start=Start;
}
This is the JSON im receiving, already filtered. (its coming from the google places autocomplete API)
{
"predictions": [
{
"description": "Frankfurt am Main, Deutschland",
"place_id": "ChIJxZZwR28JvUcRAMawKVBDIgQ",
},
{
"description": "Frankfurt (Oder), Deutschland",
"place_id": "ChIJb_u1AiqYB0cRwDteW0YgIQQ",
},
{
"description": "Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"place_id": "ChIJX3W0JgQYvkcRWBxGlm6csj0",
}
],
"status": "OK"
}
And I need to get this JSON into this format:
{
"success":true,
"message":"OK",
"data":[
{
"description":"Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"id":"ChIJX3W0JgQYvkcRWBxGlm6csj0"
},
{
"description":"Frankfurt Airport (FRA), Frankfurt am Main, Deutschland",
"id":"ChIJeflCVHQLvUcRMfP4IU3YdIo"
},
{
"description":"Frankfurt Marriott Hotel, Hamburger Allee, Frankfurt am Main, Deutschland",
"id":"ChIJdag3xFsJvUcRZtfKqZkzBAM"
}
]
}
I would be very g
So predictions is just renamed to "data", we change rename status to message, move it up and add a success if the http-request that happened earlier was a success or not. This does not seem so hard on the first catch, but I can't seem to find resources to transform or rearrange JSON in C#.
I would be very grateful for any tips or resources, so I can get unstuck on this probably not so difficult task. I should mention I'm fairly new to all of this.
Thank you all in advance!
First create classes thats represent your jsons
public class Prediction
{
public string description { get; set; }
public string place_id { get; set; }
}
public class InputJsonObj
{
public Prediction[] predictions { get; set; }
public string status { get; set; }
}
public class Datum
{
public string description { get; set; }
public string id { get; set; }
}
public class OutPutJsoObj
{
public bool success { get; set; }
public string message { get; set; }
public List<Datum> data { get; set; }
public OutPutJsoObj(){
data = new List<Datum>();
}
}
Then mapped objects (manually or using any of mapping libraries like AutoMapper) and create final json.
using Newtonsoft.Json;
InputJsonObj inputObj = JsonConvert.DeserializeObject<InputJsonObj >(inputJson);
OutPutJsoObj outObj = new OutPutJsoObj ();
foreach(var p in inputObj)
{
outObj.Data.Add(new Datum() { descriptions = p.descriptions , id= p.place_id }
}
string outJson = = JsonConvert.SerializeObject(outObj);
Just parse the origional json and move the data to the new json object
var origJsonObj = JObject.Parse(json);
var fixedJsonObj = new JObject {
new JProperty("success",true),
new JProperty("message",origJsonObj["status"]),
new JProperty("data",origJsonObj["predictions"])
};
it is not clear from your question what should be a success value, but I guess maybe you need this line too
if (fixedJsonObj["message"].ToString() != "OK") fixedJsonObj["success"] = false;
if you just need a fixed json
json = fixedJsonObj.ToString();
or you can create c# class (Data for example) and deserilize
Data result= fixedJsonObj.ToObject<Data>();
I like the answer from #Serge but if you're looking for a strongly typed approach we can model the input and output structure as the same set of classes and the output structure is similar, with the same relationships but only different or additional names this try this:
The process used here is described in this post but effectively we create write-only properties that will receive the data during the deserialization process and will format it into the properties that are expected in the output.
public class ResponseWrapper
{
[JsonProperty("success")]
public bool Success { get;set; }
[JsonProperty("message")]
public string Message { get;set; }
[Obsolete("This field should not be used anymore, please use Message instead")]
public string Status
{
get { return null; }
set
{
Message = value;
Success = value.Equals("OK", StringComparison.OrdinalIgnoreCase);
}
}
[JsonProperty("data")]
public Prediction[] Data { get;set; }
[Obsolete("This field should not be used anymore, please use Data instead")]
public Prediction[] Predictions
{
get { return null; }
set { Data = value; }
}
}
public class Prediction
{
public string description { get; set; }
public string place_id { get; set; }
}
Then you can deserialize and re-serialize with this code:
using Newtonsoft.Json;
...
var input = JsonConvert.DeserializeObject<ResponseWrapper>(input);
var output = JsonConvert.SerializeObject(objs, new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
});
This is a fiddle you can test with: https://dotnetfiddle.net/DsI5Yc
And the output:
{
"success": true,
"message": "OK",
"data": [
{
"description": "Frankfurt am Main, Deutschland",
"place_id": "ChIJxZZwR28JvUcRAMawKVBDIgQ"
},
{
"description": "Frankfurt (Oder), Deutschland",
"place_id": "ChIJb_u1AiqYB0cRwDteW0YgIQQ"
},
{
"description": "Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"place_id": "ChIJX3W0JgQYvkcRWBxGlm6csj0"
}
]
}
If you were going to go to the trouble of writing a converter for the deserialization then I find this solution is a bit simpler. I tend to use this type of solution when exposing additional properties to allow legacy data to map into a the current code base.
keeps the mapping and logic contained within the class
tells developers still writing code against the deprecated structures about the change
You can also augment this and implement a global converter to omit obsolete properties which would give you full backwards compatibility until you update the source to stop sending the legacy structure. This is a fiddle of such a solution: https://dotnetfiddle.net/MYXtGT
Inspired by these posts:
JSON.Net Ignore Property during deserialization
Is there a way to make JavaScriptSerializer ignore properties of a certain generic type?
Exclude property from serialization via custom attribute (json.net)
Json.NET: Conditional Property Serialization
I'm trying to retrieve all data from a JSON file to my C# application.
But now the problem is that the field "info" in my json file is sometimes from the type string but it can also be the type object.
{
[
{
"id":"147786",
"canUpdate":true,
"canDelete":true,
"canArchive":true,
"hasChildren":false,
"info": "Test"
},
{
"id":"147786",
"canUpdate":true,
"canDelete":true,
"canArchive":true,
"hasChildren":false,
"info": [{"id"="1","messages":"true"}]
}
]
}
well my model you can see here below, when there are only strings in my json file i can retrieve the data without any exception but when there are also objects in the info field then i get the error can't convert the value.
Is there a way to fix this on an easy way?
public string id { get; set; }
public string canUpdate { get; set; }
public string info { get; set; }
As an option you can define the info as dynamic:
public dynamic info { get; set; }
Example
Consider the following json string:
string json = #"
[
{ 'P1': 'X', 'P2': 'Y' },
{ 'P1': 'X', 'P2': [
{'P11':'XX', 'P22':'YY'},
{'P11':'XX', 'P22':'YY'}]
}
]";
You can define such model to deserialize it:
public class C
{
public string P1 { get; set; }
public dynamic P2 { get; set; }
}
And deserialize it like this:
var obj = JsonConvert.DeserializeObject<C[]>(json);
Note
If the number of dynamic properties is too much then usually there is no point in creating the class and the following code will be enough:
var obj = (dynamic)JsonConvert.DeserializeObject(json);
...and "beautiful" is sarcastic here.
When you call Active Campaign's list_view endpoint, and would like to get that in a json response, then this is the json response you get:
{
"0": {
"id": "4",
"name": "Nieuwsletter 1",
"cdate": "2018-11-22 03:44:19",
"private": "0",
"userid": "6",
"subscriber_count": 2901
},
"1": {
"id": "5",
"name": "Newsletter 2",
"cdate": "2018-11-22 05:02:41",
"private": "0",
"userid": "6",
"subscriber_count": 2229
},
"2": {
"id": "6",
"name": "Newsletter 3",
"cdate": "2018-11-22 05:02:48",
"private": "0",
"userid": "6",
"subscriber_count": 638
},
"result_code": 1,
"result_message": "Success: Something is returned",
"result_output": "json"
}
Now how would I ever be able to deserialize this to an object? Doing the normal Edit => Paste Special => Paste JSON As Classes gives me an output where I end up with classes that named _2.
Also, JsonConvert throws the following error: Accessed JObject values with invalid key value: 2. Object property name expected. So it is not really able to deserialize it either. I tried to use dynamic as object type to convert to.
The only thing I can think of now is replacing the first { by [ and the last } by ], then remove all the "1" : items and then remove the last 3 properties. After that I have a basic array which is easy convertable. But I kind of hope someone has a better solution instead of diving deep into the string.indexOf and string.Replace party...
If your key/value pair is not fixed and data must be configurable then Newtonsoft.json has one feature that to be used here and that is [JsonExtensionData]. Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case key/value pair with 0,1,2,3.......N have dynamic data so your class will be
So create one property that collects all of your dynamic key/value pair with the attribute [JsonExtensionData]. And below I create that one with name DynamicData.
class MainObj
{
[JsonExtensionData]
public Dictionary<string, JToken> DynamicData { get; set; }
public int result_code { get; set; }
public string result_message { get; set; }
public string result_output { get; set; }
}
And then you can deserialize your JSON like
string json = "Your json here"
MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json);
Edit:
If you want to collect your dynamic key's value to class then you can use below the class structure.
class MainObj
{
[JsonExtensionData]
public Dictionary<string, JToken> DynamicData { get; set; }
[JsonIgnore]
public Dictionary<string, ChildObj> ParsedData
{
get
{
return DynamicData.ToDictionary(x => x.Key, y => y.Value.ToObject<ChildObj>());
}
}
public int result_code { get; set; }
public string result_message { get; set; }
public string result_output { get; set; }
}
public class ChildObj
{
public string id { get; set; }
public string name { get; set; }
public string cdate { get; set; }
public string _private { get; set; }
public string userid { get; set; }
public int subscriber_count { get; set; }
}
And then you can deserialize your JSON like
MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json);
And then you can access each of your deserialized data like
int result_code = mainObj.result_code;
string result_message = mainObj.result_message;
string result_output = mainObj.result_output;
foreach (var item in mainObj.ParsedData)
{
string key = item.Key;
ChildObj childObj = item.Value;
string id = childObj.id;
string name = childObj.name;
string cdate = childObj.cdate;
string _private = childObj._private;
string userid = childObj.userid;
int subscriber_count = childObj.subscriber_count;
}
I'd recommend JObject from the Newtonsoft.Json library
e.g. using C# interactive
// Assuming you've installed v10.0.1 of Newtonsoft.Json using a recent version of nuget
#r "c:\Users\MyAccount\.nuget\.nuget\packages\Newtonsoft.Json\10.0.1\lib\net45\Newtonsoft.Json.dll"
using Newtonsoft.Json.Linq;
var jobj = JObject.Parse(File.ReadAllText(#"c:\code\sample.json"));
foreach (var item in jobj)
{
if (int.TryParse(item.Key, out int value))
{
Console.WriteLine((string)item.Value["id"]);
// You could then convert the object to a strongly typed version
var listItem = item.Value.ToObject<YourObject>();
}
}
Which outputs:
4
5
6
See this page for more detail
https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
I feel like I'm making this much harder than it needs to be.
In C# using Netwonsoft JSON Compact with external data. Trying to figure out how to deserialize/parse data that looks like
{"http":{"0":{"title":"arbitrary","value":"arbitrary"},"1":{"title":"arbitrary","value":"arbitrary"}},"sip":{"1003":{"title":"arbitrary","value":"none"}}}
It's essentially an array of notifications and the ID -- "0", "1", and "1003" in the above examples is an arbitrary value and appears to have a valid range of 0 and roughly 65535.
But it's not formatted as an array (or I wouldn't be here) -- need help figuring out how to deserialize the value object while essentially ignoring the string identifier.
Thanks in advance
You can't easily deserialize it as an array, but you can deserialize it to a dictionary with integer keys. I don't know about Json.NET Compact, but this works fine with regular Json.NET:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Root
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Property
{
public string Title { get; set; }
public string Value { get; set; }
}
class Test
{
static void Main()
{
string json = File.ReadAllText("test.json");
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var entry in root.Http)
{
Console.WriteLine($"{entry.Key}: {entry.Value.Title}/{entry.Value.Value}");
}
}
}
If you really need the properties as arrays, I'd suggest having two separate classes: one for the JSON representation, and then another for real usage. For example:
class RootJson
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Root
{
// TODO: Control access more :)
public Property[] Http { get; set; }
public Property[] Sip { get; set; }
}
Then:
var rootJson = ...;
var root = new Root
{
Http = rootJson.Http.Values.ToArray(),
Sip = rootJson.Sip.Values.ToArray(),
};
If you can't change the structure of the JSON, you can always do something like this. The dynamic type figures out what to do on runtime.
dynamic d = JsonConvert.DeserializeObject("{'http':{'0':{'title':'arbitrary','value':'arbitrary'},'1':{'title':'arbitrary','value':'arbitrary'}},'sip':{'1003':{'title':'arbitrary','value':'none'}}}");
Console.WriteLine(d.http["0"].title); // arbitrary
foreach(var prop in d.http) {
Console.WriteLine(prop);
}
foreach(var prop in d.sip) {
Console.WriteLine(prop);
}
Final output:
arbitrary
"0": {
"title": "arbitrary",
"value": "arbitrary"
}
"1": {
"title": "arbitrary",
"value": "arbitrary"
}
"1003": {
"title": "arbitrary",
"value": "none"
}