Json response transformed into new json format c# - 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.

Related

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

{
"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');

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

How Can I Use Foreach In This Json Line?

I'm using RestSharp in my app and I need to iterate some part in a code.
request.AddParameter("undefined", "{\r\n \"targetType\": \"SYSTEM\",\r\n \"name\": \"xxxxxxxxxx\",\r\n \"message\": \"Daily usage exceeded\",\r\n \"active\": true,\r\n \"emails\": [\"machin#truc.com\"],\r\n \"conditions\": [{\r\n \"operator\": \"EQUALS\",\r\n \"operands\": [\r\n {\r\n \"attributeId\": \r\n {\r\n \"name\": \"system.usage.status\"\r\n }\r\n \r\n }, \r\n {\r\n \"valueStr\": \"nearing plan\"\r\n }\r\n ]\r\n },\r\n {\r\n \"operator\": \"EQUALS\",\r\n \"operands\": [\r\n {\r\n \"attributeId\": \r\n {\r\n \"name\": \"system.name\"\r\n }\r\n \r\n }, \r\n {\r\n \"valueStr\": \"SIM 89332401000006726968\"\r\n \r\n }\r\n ]\r\n },\r\n {\r\n \"operator\": \"EQUALS\",\r\n \"operands\": [\r\n {\r\n \"attributeId\": \r\n {\r\n \"name\": \"system.name\"\r\n }\r\n \r\n }, \r\n {\r\n \"valueStr\": \"SIM 89332401000006726968\"\r\n \r\n }\r\n ]\r\n }\r\n \r\n ]\r\n}", ParameterType.RequestBody);
How can I iterate that part with foreach?
{\r\n \"operator\": \"EQUALS\",\r\n \"operands\": [\r\n {\r\n \"attributeId\": \r\n {\r\n \"name\": \"system.name\"\r\n }\r\n \r\n }, \r\n {\r\n \"valueStr\": \"SIM 89332401000006726968\"\r\n \r\n }\r\n ]\r\n }\r\n
Create class which represents your json structure, take some help from http://json2csharp.com/
public class AttributeId
{
public string name { get; set; }
}
public class Operand
{
public AttributeId attributeId { get; set; }
public string valueStr { get; set; }
}
public class Condition
{
public string #operator { get; set; }
public List<Operand> operands { get; set; }
}
public class RootObject
{
public string targetType { get; set; }
public string name { get; set; }
public string message { get; set; }
public bool active { get; set; }
public List<string> emails { get; set; }
public List<Condition> conditions { get; set; }
}
After that,
var myJsonObject = JsonConvert.DeserializeObject<RootObject>(yourJsonString);
and then iterate on myJsonObject.conditions

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; }
}

Serialize an ASP.NET MVC model in JSON

I have a model like this
public class Category : BaseFieldsTables
{
public ICollection<Category> Categories { get; set; }
public Category Parent { get; set; }
public int? ParentId { get; set; }
}
i want to serialize the model to json and this is my controller
var categories =
_efCategory.List().ToList().
ToList().
Select(x => new {id = x.Id, title = x.Name, children = x.Parent});
string output = JsonConvert.SerializeObject(categories, Formatting.Indented,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
return Json(output.Replace, JsonRequestBehavior.AllowGet);
but i get this result
"[\r\n {\r\n \"$id\": \"1\",\r\n \"id\": 1,\r\n \"title\": \"News\",\r\n \"children\": null\r\n },\r\n {\r\n \"$id\": \"2\",\r\n \"id\": 2,\r\n \"title\": \"2012\",\r\n \"children\":
{\r\n \"$id\": \"3\",\r\n \"Categories\": [\r\n {\r\n \"$id\":
This is normal. All you are seeing is the escaped version of your string (probably directly in Visual Studio). \r\n is the equivalent of a newline character and \" is just a means to escape the ". Outputted, this should appear as normal.

Categories