Convert json dynamic content to C# object (or dictionary) - c#

{
"results": [
{
"content1": {
"prop1" : "value1",
"prop2" : "value2"
},
"content2": {
"prop1" : "value1",
"prop2" : "value2"
},
"contentn": {
"prop1" : "value1",
"prop2" : "value2"
}
}
]
}
I am having trouble converting this json to a dynamic C# object, the case here is that 'content1' to 'content' will always be different and dynamic content and I do need to convert it to something like a dictionary.
The idea is to reduce the classes as, I will need to create tons of them.
PS: I am using a 3rd party api that's returning the data as above.
Tried numerous ways to handle this.
JsonConvert to try to map to Dictionary, List and the same for JsonSerializer.Deserialize

The solution below uses System.Text.Json
Create a Content class:
public class Content
{
public string prop1 { get; set; }
public string prop2 { get; set; }
}
and now you can deserialize:
var data = "{\r\n \"results\": [\r\n {\r\n \"content1\": {\r\n \"prop1\" : \"value1\",\r\n \"prop2\" : \"value2\"\r\n },\r\n \"content2\": {\r\n \"prop1\" : \"value1\",\r\n \"prop2\" : \"value2\"\r\n },\r\n \"contentn\": {\r\n \"prop1\" : \"value1\",\r\n \"prop2\" : \"value2\"\r\n }\r\n }\r\n ]\r\n}";
var serData = JsonSerializer.Deserialize<Dictionary<string, List<object>>>(data);
var myResults = serData.First().Value[0].ToString();
if(!string.IsNullOrEmpty(myResults))
{
var myDynamicObjects = JsonSerializer.Deserialize<Dictionary<string, Content>>(myResults);
}

You can try with the ExpandoObject very powerfull for that kind of jobs.
static async Task Main(string[] _)
{
var dynamicReturn = await new HttpClient().GetFromJsonAsync<ExpandoObject>("https://run.mocky.io/v3/dab5a150-40a9-4520-a809-ff5484489fe9");
foreach (var kvp in dynamicReturn)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}
}

you can try this code
// using Newtonsoft.Json;
Dictionary<string, Content> content = JObject.Parse(json)["results"][0]
.ToObject<Dictionary<string, Content>>();
//or
// using System.Text.Json
Dictionary<string, Content> content = System.Text.Json.Nodes.JsonNode
.Parse(json)["results"][0]
.Deserialize<Dictionary<string, Content>>();
class
public class Content
{
public string prop1 { get; set; }
public string prop2 { get; set; }
}

try this::
public class Content
{
public string Prop1{ get; set; }
public string Prop2 { get; set; }
}
var people = JsonConvert.DeserializeObject<List<Content>>('your json data');

Related

Json response transformed into new json format c#

I'm trying to convert a json input format into another json format by using c#.
The input format which is seen just below is gotten from a httpclient post request:
{
"data": {
"trafficData": {
"volume": {
"byHour": {
"edges": [
{
"node": {
"from": "2019-10-24T12:00:00+02:00",
"to": "2019-10-24T13:00:00+02:00",
"byDirection": [
{
"heading": "North",
"total": {
"volumeNumbers": {
"volume": 696
}
}
},
{
"heading": "South",
"total": {
"volumeNumbers": {
"volume": 726
}
}
}
]
}
},
{
"node": {
"from": "2019-10-24T13:00:00+02:00",
"to": "2019-10-24T14:00:00+02:00",
"byDirection": [
{
"heading": "North",
"total": {
"volumeNumbers": {
"volume": 805
}
}
},
{
"heading": "South",
"total": {
"volumeNumbers": {
"volume": 751
}
}
}
]
}
}
]
}
}
}
}
}
I wish to transform the json input to something similar to the output code just below:
{
"data":[
{
"from":"2019-10-24T12:00:00+02:00",
"to":"2019-10-24T13:00:00+02:00",
"heading":"South",
"volume":726
},
{
"from":"2019-10-24T13:00:00+02:00",
"to":"2019-10-24T14:00:00+02:00",
"heading":"South",
"volume":751
}
]
}
In c# i have tried the below code: (also in connection with creating new class objects with https://json2csharp.com/)
//o1 is the json object input
IEnumerable<JToken> jTokens = o1.Descendants().Where(p => !p.HasValues);
Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) =>
{
properties.Add(jToken.Path, jToken.ToString());
return properties;
});
try this code
json = new JArray(JObject.Parse(json).SelectToken("data.trafficData.volume.byHour.edges")
.Select(o => new JObject
{
["from"] = (string)o["node"]["from"],
["to"] = (string)o["node"]["to"],
["byDirection"] = new JArray(o["node"]["byDirection"]
.Select(o => new JObject
{
["heading"] = o["heading"],
["volume"] = o["total"]["volumeNumbers"]["volume"]
}))
})).ToString();
I would personally use AutoMapper in this case.
My answer will be written using .NET 6 Web API model (with AutoMapper package obviously installed first).
I generated the C# classes with the tool you provided for my example.
Let's assume I have a Request.cs file as :
using System.Text.Json.Serialization;
namespace Something.Requests
{
// Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse);
public class ByDirection
{
[JsonPropertyName("heading")]
public string heading { get; set; }
[JsonPropertyName("total")]
public Total total { get; set; }
}
public class ByHour
{
[JsonPropertyName("edges")]
public List<Edge> edges { get; set; }
}
public class Data
{
[JsonPropertyName("trafficData")]
public TrafficData trafficData { get; set; }
}
public class Edge
{
[JsonPropertyName("node")]
public Node node { get; set; }
}
public class Node
{
[JsonPropertyName("from")]
public DateTime from { get; set; }
[JsonPropertyName("to")]
public DateTime to { get; set; }
[JsonPropertyName("byDirection")]
public List<ByDirection> byDirection { get; set; }
}
public class Request
{
[JsonPropertyName("data")]
public Data data { get; set; }
}
public class Total
{
[JsonPropertyName("volumeNumbers")]
public VolumeNumbers volumeNumbers { get; set; }
}
public class TrafficData
{
[JsonPropertyName("volume")]
public Volume volume { get; set; }
}
public class Volume
{
[JsonPropertyName("byHour")]
public ByHour byHour { get; set; }
}
public class VolumeNumbers
{
[JsonPropertyName("volume")]
public int volume { get; set; }
}
}
Using your tool, I also created a Response.cs like this :
using System.Text.Json.Serialization;
namespace Something.Answers
{
public class Datum
{
[JsonPropertyName("from")]
public DateTime from { get; set; }
[JsonPropertyName("to")]
public DateTime to { get; set; }
[JsonPropertyName("heading")]
public string heading { get; set; }
[JsonPropertyName("volume")]
public int volume { get; set; }
}
public class Result
{
[JsonPropertyName("data")]
public List<Datum> data { get; set; }
}
}
In order to handle mapping between the two type of objects, I would create a MappingConfiguration like so :
namespace Something.Mapper
{
public class MappingConfiguration : Profile
{
public MappingConfiguration()
{
// TEST
CreateMap<Something.Requests.Node, Something.Answers.Datum>()
.ForMember(datum => datum.from, opt => opt.MapFrom(node => node.from))
.ForMember(datum => datum.to, opt => opt.MapFrom(node => node.to))
.ForMember(datum => datum.heading, opt => opt.MapFrom(node => node.byDirection.FirstOrDefault().heading))
.ForMember(datum => datum.volume, opt => opt.MapFrom(node => node.byDirection.FirstOrDefault().total.volumeNumbers))
.ReverseMap();
}
}
}
In my Program.cs, I would then Dependency Inject my MappingConfiguration with code below, before my "builder.Build()" :
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingConfiguration());
});
IMapper mapper = mappingConfig.CreateMapper();
builder.Services.AddSingleton(mapper);
Finally, within my business class, I can do something like this:
var jsonRequest = "{\r\n \"data\": {\r\n \"trafficData\": {\r\n \"volume\": {\r\n \"byHour\": {\r\n \"edges\": [\r\n {\r\n \"node\": {\r\n \"from\": \"2019-10-24T12:00:00+02:00\",\r\n \"to\": \"2019-10-24T13:00:00+02:00\",\r\n \"byDirection\": [\r\n {\r\n \"heading\": \"North\",\r\n \"total\": {\r\n \"volumeNumbers\": {\r\n \"volume\": 696\r\n }\r\n }\r\n },\r\n {\r\n \"heading\": \"South\",\r\n \"total\": {\r\n \"volumeNumbers\": {\r\n \"volume\": 726\r\n }\r\n }\r\n }\r\n ]\r\n }\r\n },\r\n {\r\n \"node\": {\r\n \"from\": \"2019-10-24T13:00:00+02:00\",\r\n \"to\": \"2019-10-24T14:00:00+02:00\",\r\n \"byDirection\": [\r\n {\r\n \"heading\": \"North\",\r\n \"total\": {\r\n \"volumeNumbers\": {\r\n \"volume\": 805\r\n }\r\n }\r\n },\r\n {\r\n \"heading\": \"South\",\r\n \"total\": {\r\n \"volumeNumbers\": {\r\n \"volume\": 751\r\n }\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n }\r\n }\r\n}";
Something.Requests.Request myRequest = JsonSerializer.Deserialize<Something.Requests.Request>(jsonRequest);
List<Something.Answers.Datum> data= new List<Something.Answers.Datum>();
foreach(var edge in myRequest.data.trafficData.volume.byHour.edges)
{
var tmp = _mapper.Map<Something.Requests.Node>(edge.node);
}
var jsonAnswer = JsonSerializer.Serialize(data);
Hope this gives you an alternative.

find a match with an element in my class c#

I have the following JSON string
{ "Params": [ { "name": "id","value": "1234567" },
{ "name": "class","value": "six"}
],
"type":"general"}
and equivalent class as below
public class class1
{
public Param[] Params { get; set; }
public string Type { get; set; }
}
public class Param
{
public string Name { get; set; }
public string Value { get; set; }
}
How can I search if there is an object with name as id in Params array and how to fetch its value?
Include Newtonsoft.Json
using Newtonsoft.Json;
Then deserialize your json string to an object of class1, then search using linq.
string json = "{\"Params\": [ { \"name\": \"id\",\"value\": \"1234567\" },{ \"name\": \"class\",\"value\": \"six\"}],\"type\":\"general\"}";
// convert to object
var jsonObject = JsonConvert.DeserializeObject<class1>(json);
// filter
var result = jsonObject.Params.Where(p=> p.Name == "id" && p.Value == "1234567");
The Json.net documentation has a pretty good example you can use as well. It shows a way to do without necessarily converting to a C# object. See below
https://www.newtonsoft.com/json/help/html/queryinglinqtojson.htm

Deserializing Json to an Array type Propoerty

I am new to Json. I am trying to populate my object 'Sources' from json string with:
public class Sources
{
public long[] SourceIds;
}
string jsonstring = " [\r\n {\r\n \"SourceIds\": 20181234\r\n }, \r\n
{\r\n \"SourceIds\": 20181234\r\n },\r\n {\r\n \"SourceIds\":
20181234\r\n }\r\n]"
My aim is to have an object of 'Sources' with the values of 'SourceIds' populated.
Thanks in advance,
I suspect that your actual Json is like below:
string jsonstring = " [
{
\"SourceIds\": 20181234
},
{
\"SourceIds\": 20181234
},
{
\"SourceIds\": 20181234
}
]"
You can serialize your json with
var result = JsonConvert.DeserializeObject<IList<Class1>>(String)
Serialization Classes
public class Class1
{
public int SourceIds { get; set; }
}
Fiddle

After Deserialize Object result have extra brackets

Here is my data coming from ajax post.
string form = "[{\"id\": \"1\", \"name\": \"deneme\"},{\"id\": \"2\", \"name\": \"deneme2\"}]"
When I deserialize like this:
var data = JsonConvert.DeserializeObject(form);
The object is like this:
{ [{"id": 1, "name": "deneme"},{"id": 2, "name": "deneme2"}] }
How can I solve this problem?
Edit:
[HttpPost]
public HttpResponseMessage ImportFromExcel(string form, string controller, string action)
{
//form = "[{\"id\": \"1\", \"name\": \"deneme\"},{\"id\": \"2\", \"name\": \"deneme2\"}]"
ImportObject _importObject = new ImportObject();
_importObject.SchemaName = controller;
_importObject.TableName = action;
var deger = JsonConvert.DeserializeObject(form);
//deger = { [{"id": 1, "name": "deneme"},{"id": 2, "name": "deneme2"}] }
Utility.HttpPostJson(proUtil.GetConfigStr("ApiImportUrl", ""), "Import", JsonConvert.SerializeObject(_importObject));
return new HttpResponseMessage(HttpStatusCode.Created);
}
public class ImportObject
{
public string SchemaName { get; set; }
public string TableName { get; set; }
public List<string> DataSet { get; set; }
}
So you are deserialising into JSON.Net objects instead of using a proper concrete class structure. I would recommend doing something like this. First make a class to hold your data:
public class FormItem
{
public int Id { get; set; }
public string Name { get; set; }
}
Now deserialise into an IEnumerable<FormItem> like this:
var data = JsonConvert.DeserializeObject<IEnumerable<FormItem>>(form);
And now you can loop through it as you would any other enumerable:
foreach(var formItem in data)
{
Console.WriteLine($"Item with id of {formItem.Id} has a name of {formItem.Name}");
}
The Solution is:
var form = JsonConvert.DeserializeObject<List<object>>(comingData.ToString());
foreach (var item in form)
{
var cSharpClass = JsonConvert.DeserializeObject<dynamic>(item.ToString());
foreach (JProperty item2 in cSharpClass)
{
Console.WriteLine(item2.Name);
Console.WriteLine(item2.Value);
}
}

Newtonsoft JSON - different JSON structure, object vs array [duplicate]

This question already has answers here:
How to handle both a single item and an array for the same property using JSON.net
(9 answers)
Closed 5 years ago.
I have this JSON structure:
[
{
"key1": "value",
"key2": "value",
"key3": "TYPE_ONE",
"extraData": {
"key4": "value",
"key5": "value",
"key6": {
"key7": {
"key8": "value",
"key9": "value",
"key10": "value"
}
}
}
},
{
"key1": "value",
"key2": "value",
"key3": "TYPE_TWO",
"extraData": {
"key4": "value",
"key5": "value",
"key6": {
"key7": [
{
"key8": "value",
"key9": "value",
"key10": "value"
},
{
"key8": "value1",
"key9": "value1",
"key10": "value1"
},
{
"key8": "value2",
"key9": "value2",
"key10": "value2"
}
]
}
}
}
]
I'm trying to deserialize it with using Newtonsoft.Json; in C#. JSON has two structures.
1. CASE -> when "key3": "TYPE_ONE", then key7 is object.
2. CASE -> when "key3": "TYPE_TWO", Then key7 is array.
If in class
public class key6
{
public key7 key7Item { get; set; }
}
key7Item is set as object works only if i get all object from response that are
"key3": "TYPE_ONE"
If i set key7Item as List then works only if all items from response are "key3": "TYPE_TWO".
Can i configure Newtonsoft parser to parse array if it got array or object if it got object?
Short answer - don't do this if you can possibly avoid it. You'll save yourself lots of complexity by giving the array a different key name.
Long answer, you can do it, but it's painful. If anyone knows how to do with without re-serializing the j-objects that are generated (i.e. keeping the json alongside the deserialized objects), I'd love to know:
private static readonly string Json = "[\r\n {\r\n \"key1\": \"value\",\r\n \"key2\": \"value\",\r\n \"key3\": \"TYPE_ONE\",\r\n \"extraData\": {\r\n \"key4\": \"value\",\r\n \"key5\": \"value\",\r\n \"key6\": {\r\n \"key7\": {\r\n \"key8\": \"value\",\r\n \"key9\": \"value\",\r\n \"key10\": \"value\"\r\n }\r\n }\r\n }\r\n },\r\n {\r\n \"key1\": \"value\",\r\n \"key2\": \"value\",\r\n \"key3\": \"TYPE_TWO\",\r\n \"extraData\": {\r\n \"key4\": \"value\",\r\n \"key5\": \"value\",\r\n \"key6\": {\r\n \"key7\": [\r\n {\r\n \"key8\": \"value\",\r\n \"key9\": \"value\",\r\n \"key10\": \"value\"\r\n },\r\n {\r\n \"key8\": \"value1\",\r\n \"key9\": \"value1\",\r\n \"key10\": \"value1\"\r\n },\r\n {\r\n \"key8\": \"value2\",\r\n \"key9\": \"value2\",\r\n \"key10\": \"value2\"\r\n }\r\n ]\r\n }\r\n }\r\n }\r\n]";
private static void Deserialize()
{
var switchers = JsonConvert.DeserializeObject<JObject[]>(Json);
var deserializedType1List = new List<TargetClass<Key6Type1>>();
var deserializedType2List = new List<TargetClass<Key6Type2>>();
foreach (var switcher in switchers)
{
if (switcher["key3"].Value<string>() == "TYPE_ONE")
{
deserializedType1List.Add(JsonConvert.DeserializeObject<TargetClass<Key6Type1>>(JsonConvert.SerializeObject(switcher)));
}
else
{
deserializedType2List.Add(JsonConvert.DeserializeObject<TargetClass<Key6Type2>>(JsonConvert.SerializeObject(switcher)));
}
}
//Do something with the objects...
}
private class TargetClass<TKey6Type>
{
public string key1 { get; set; }
public string key2 { get; set; }
public string key3 { get; set; }
public ExtraData<TKey6Type> extraData { get; set; }
}
private class ExtraData<TKey6Type>
{
public string key4 { get; set; }
public string key5 { get; set; }
public TKey6Type key6 { get; set; }
}
private class Key6Type2
{
public Key7[] key7 { get; set; }
}
private class Key6Type1
{
public Key7 key7 { get; set; }
}
private class Key7
{
public string key8 { get; set; }
public string key9 { get; set; }
public string key10 { get; set; }
}

Categories