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

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

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.

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

Parsing Array of objects JSON in C#

My JSON Input is below. Sry it is too long
{
"status":{
"success":[
{
"User":{
"id":"1377",
"username":"Dr.Hema Sathish",
"username_url":"dr-hema-sathish",
"firstname":null,
"lastname":null,
"email":"madurai#sancheclinic.com",
"password":"6c7ab07e828828206e3d7c56c3c35cfd383960cd",
"user_level":"doctor"
},
"Speciality":{
"id":"2",
"name":"Dermatology(Skin Specialist)",
"slug":"dermatology-skin-specialist",
"image":"1438693213.png",
"status":"1",
"created":"2015-07-08 03:35:57",
"modified":"2016-09-13 13:58:36"
}
}
]
}
}
I have downloaded JSON String from URL Successfully.
static void main
{
using (var webClient = new System.Net.WebClient())
{
string json = webClient.DownloadString("http://myURL/");
Console.WriteLine(json.ToString());
}
}
Now I have to get User and Speciality objects. Its confusing to parse Array of Objects Json. How to parse it?
I have tried Deserialization. But it does not work.
How to parse it?
Your json is invalid...here is correct json
{
"status": {
"success": [{
"User": {
"id": "1377",
"username": "Dr.Hema Sathish"
},
"Speciality": {
"id": "2",
"name": "Dermatology(Skin Specialist)"
}
},
{
"User": {
"id": "1390",
"username": "Dr.Nichita Balaji"
},
"Speciality": {
"id": "2",
"name": "Dermatology(Skin Specialist)"
}
}
]
}
}
You can create below classes to deserialize it using Newtonsoft
public class User
{
public string id { get; set; }
public string username { get; set; }
}
public class Speciality
{
public string id { get; set; }
public string name { get; set; }
}
public class Success
{
public User User { get; set; }
public Speciality Speciality { get; set; }
}
public class Status
{
public List<Success> success { get; set; }
}
public class RootObject
{
public Status status { get; set; }
}
Here is the code to deserialize it
string json =
" {\r\n \t\"status\": {\r\n \t\t\"success\": [{\r\n \t\t\t\t\"User\": {\r\n \t\t\t\t\t\"id\": \"1377\",\r\n \t\t\t\t\t\"username\": \"Dr.Hema Sathish\"\r\n \t\t\t\t},\r\n \t\t\t\t\"Speciality\": {\r\n \t\t\t\t\t\"id\": \"2\",\r\n \t\t\t\t\t\"name\": \"Dermatology(Skin Specialist)\"\r\n \t\t\t\t}\r\n \t\t\t},\r\n \t\t\t{\r\n \t\t\t\t\"User\": {\r\n \t\t\t\t\t\"id\": \"1390\",\r\n \t\t\t\t\t\"username\": \"Dr.Nichita Balaji\"\r\n \t\t\t\t},\r\n \t\t\t\t\"Speciality\": {\r\n \t\t\t\t\t\"id\": \"2\",\r\n \t\t\t\t\t\"name\": \"Dermatology(Skin Specialist)\"\r\n \t\t\t\t}\r\n\r\n \t\t\t}\r\n \t\t]\r\n \t}\r\n }";
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(json);
var successes = rootObject.status.success;
var specialityObjects = successes.Select(success => success.Speciality).ToList();
var users = successes.Select(success => success.User).ToList();
Console.WriteLine(users[0].id + " " + users[0].username);
Console.WriteLine(users[1].id + " " + users[1].username);
Console.WriteLine(specialityObjects[0].id + " " + specialityObjects[0].name);
Console.WriteLine(specialityObjects[1].id + " " + specialityObjects[1].name);
Console.ReadLine();
//OUTPUT
1377 Dr.Hema Sathish
1390 Dr.Nichita Balaji
2 Dermatology(Skin Specialist)
2 Dermatology(Skin Specialist)
You have to create classes according to JSON data set :
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
}
public class Speciality
{
public int Id { get; set; }
public string Name { get; set; }
}
Then, you should be able to Deserialize using JSON .NET library
string json = webClient.DownloadString("http://myURL/");
User u = JsonConvert.DeserializeObject<User>(json);
There may be other library available, nonetheless this one is working fine (and is available as NuGET package).
Please note this is only a sample, your code will miss several classes to properly parse your JSON (Status class, etc.).

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