Convert complex Json to Object - c#

I have a following JSON response:
{
"data": [
{
"ac_conditions": "[{\"ac_condition_group_id\":156570,\"ac_condition_group_name\":\"\u0413\u0440\u0443\u043f\u043f\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 1\",\"id\":311790,\"ac_parameter\":\"utm_source\",\"ac_operator\":\"=\",\"value\":\"google_rem\",\"is_negative\":false},{\"ac_condition_group_id\":156570,\"ac_condition_group_name\":\"\u0413\u0440\u0443\u043f\u043f\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 1\",\"id\":275094,\"ac_parameter\":\"utm_source\",\"ac_operator\":\"=\",\"value\":\"yandex_retargeting\",\"is_negative\":false}]",
"is_dt_enabled": true,
"ac_id": 162866,
"site_blocks": "[{\"id\":324164,\"name\":\"\u041d\u043e\u043c\u0435\u0440 1 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435\",\"phone_type\":\"virtual\",\"numb\":\"74950238629\",\"forward_numb\":null,\"is_dt_enabled\":true,\"dt_number_pool_numbers\":[\"74951828912\",\"74950324045\",\"74950324046\",\"74950324043\",\"74950324037\",\"74951828907\",\"74950324048\",\"74950324049\",\"74951523589\",\"74953239984\"]}]"
}
],
"success": true
}
I create a class to deserealize it
public class Condition
{
public bool success;
public List<Data> data;
public class Data
{
public string ac_conditions;
public int ac_id;
public bool is_dt_enabled;
public string site_blocks;
};
}
It's working fine. What I need is to deserealize also the elements ac_conditions and site_blocks. I have created a new class but I get an exception (System.String cannot cast to List)
public class Condition
{
public bool success;
public List<Data> data;
public class Data
{
public List<ConditionCamp> ac_conditions;
public int ac_id;
public bool is_dt_enabled;
public List<SiteBlock> site_blocks;
public class ConditionCamp
{
public int ac_condition_group_id;
public string ac_condition_group_name;
public int id;
public string ac_parameter;
public string ac_operator;
public string value;
public bool is_negative;
}
public class SiteBlock
{
public int id;
public string name;
public string phone_type;
public string numb;
public string forward_numb;
public bool is_dt_enabled;
public string dt_number_pool_numbers;
}
};
}
I use this line in my code to deserialize the JSON response
JsonConvert.DeserializeObject<Models.Condition>(string_Condition);

Your JSON property "site_blocks" is a string value containing serialized JSON-data. Therefore you need a second step to unwrap/deserialize the data. If you can change the the way how the response is generated you can fix it there (return JSON in site_blocks and no string)
E.g. (using Json.net and results of second parse run are store in site_blocks_parsed)
public class Condition
{
public bool success;
public List<Data> data;
public class Data
{
public string ac_conditions;
public int ac_id;
public bool is_dt_enabled;
public string site_blocks;
public List<SiteBlock> site_blocks_parsed;
public class ConditionCamp
{
public int ac_condition_group_id;
public string ac_condition_group_name;
public int id;
public string ac_parameter;
public string ac_operator;
public string value;
public bool is_negative;
}
public class SiteBlock
{
public int id;
public string name;
public string phone_type;
public string numb;
public string forward_numb;
public bool is_dt_enabled;
public string dt_number_pool_numbers;
}
};
}
...
var condition = JsonConvert.DeserializeObject<Condition>(jsonString);
foreach (var data in condition.data) {
data.site_blocks_parsed = JsonConvert.DeserializeObject<List<SiteBlock>>(data.site_blocks);
}

Related

restrict a setter to a static list of values

I have the following models
public class CustomEvent
{
private string _tag;
public int Id { get; set; }
public int PId { get; set; }
public DateTimeOffset TimeStamp { get; set; }
public string Mentor { get; set; }
public string Type { get; set; }
public string Tag
{
get => _tag;
set
{
_tag = GetTagTypeList.GetTagType(typeof(TagType)).Contains(value) ? value : "Unspecified";
}
}
}
public static class TagType
{
public const string Unspecified = "Unspecified";
public const string AmxPersonalItemCreate = "Amx.PersonalItem.Create";
public const string AmxPersonalItemUpdate = "Amx.PersonalItem.Update";
public const string AmxPersonalItemDelete = "Amx.PersonalItem.Delete";
public const string AmxRegionCreate = "Amx.Region.Create";
public const string AmxRegionUpdate = "Amx.Region.Delete";
public const string AmxRegionDelete = "Amx.Region.Update";
}
public class GetTagTypeList
{
public static List<String> GetTagType(Type type)
{
return type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Select(x=>x.GetValue(null).ToString()).ToList();
}
}
The above code restricts the setter to the list of static values. However this is very inefficient, as it is reflecting over the class every single time the method [GetTagType] is called.
I now have a requirement to Create a TagType class with a private constructor, and static values.
Given the values to be expressed have "." in them, it will require a custom json serializer as well.
I have read somewhere that a solution could be to use nested classes to get values which match the string being created.
i.e. for "Amx.PersonalItem.Create" we could create a class which resemble:
public static class Amx
{
public static class PersonalItem
{
public static TagType Create { get; } = new TagType("Amx.PersonalItem.Create");
}
}
I need to integrate the above example into my CustomEvent Class.
Or any other solution that uses static values to achieve same result.
Would appreciate any help ?
How about making a static item in the class that builds the list and stores it in a static variable? That means you can build the list once no matter how many times your setter is called. You still have to search the list but you don't need to use reflection.

Newtonsoft.Json parsing json from webpage doesn't work

I've made a simple program that gets json from a website. It should give out some of the json attributes, but it doesn't do it. It simply gives me a clear String without text in it. Can someone help me?
My Code:
using System;
using System.Linq;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.IO;
using Newtonsoft.Json;
namespace ESEL_Scraper_2._0
{
class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
class Program
{
static void Main(string[] args)
{
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<MyJsonType>(site);
Console.WriteLine(myJsonObject.title);
}
}
}
The JSON: https://esel.at/api/termine/data?date=05.09.2020&selection=false
MyJsonType expects the body to be like,
{
"id": 1,
"title": "title"
}
but in your case, the json is,
{
"termine": [
{ -> object }
{ -> object }
]
}
You have an array of Objects that fit into your MyJsonType. Use the following class to deserialize to
public class RootObject
{
[JsonProperty("termine")] // the name of the property is case sensetive.
public List<MyJsonType> Termine {get;set;}
}
public class MyJsonType
{
[JsonProperty("title")]
public string Title { get; set; } //C# uses uppercase first letter for properties.
[JsonProperty("id")]
public int Id { get; set; }
}
// in your main,
var obj = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(obj.Termine.First().Title);
You need to structure your call as per your json string.
You class should look like this
public class ParentJsonType
{
public List<MyJsonType> termine { get; set; }
}
public class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
and in your code you can deserialize
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<List<MyJsonType>>(site);
foreach(var myJosnType in myJsonObject)
{
//add your logic here
Console.WriteLine(myJosnType.title);
}
Yes, guys that already answered are absolutely right.
The point is in the wrong model you have, which has no necessary structure to contain a responded context.
The following approach is also working. The correct model for that JSON should be:
public class Termine
{
public Int64 id {get;set;}//":106102,
public String title {get;set;}//":"curated by 2020",
public String category {get;set;}//":"eSeLs Neugierde",
public String startdate {get;set;}//":"Sa, 05.09.2020",
public String startdatetime {get;set;}//":"Sa, 05.09. 11:00",
public String starttime {get;set;}//":"11:00",
public String enddate {get;set;}//":"Sa, 05.09.2020",
public List<object> runtime {get;set;}//":[ 0, "nur noch heute" ],
public String thumbnail {get;set;}//":"https:\/\/static.esel.at\/mini\/\/upload\/IpeP5wgYL7sRucTuFtpJg53zgG7hby5IiXv5txLk.jpeg",
public String thumbnail_credits {get;set;}//":null,
public String type {get;set;}//":"upcoming",
public String recommended {get;set;}//":"(Wie) Schafft's Kunst als Aktivismus in Galerier\u00e4ume?`",
public Boolean online_event {get;set;}//":false,
public String feed_urls {get;set;}//":null,
public String status {get;set;}//":"",
public String tags {get;set;}//":"Galerienfestival, internationale KuratorInnen, Aktivismus, Kunst, curatedby",
public String url {get;set;}//":"https:\/\/esel.at\/termin\/106102\/curated-by-2020",
public DateTime sort_date {get;set;}//":"2020-09-05 11:00:00",
public String sort_category {get;set;}//":"eselsneugierde",
public String location_url {get;set;}//":"https:\/\/esel.at\/location\/933\/wien",
public String location {get;set;}//":"Wien"
public override String ToString(){
return String.Format("[{0}] {1} ({2})", this.id, this.title, this.location_url);
}
}
public class Meta
{
public List<String> next {get;set;}//":[ "Sonntag,<br><nobr>06. September 2020<\/nobr>", "06.09.2020", "06092020" ],
public DateTime now {get;set;}//":"2020-09-05T18:52:05.000040Z",
public List<String> da {get;set;}//":[ "Samstag,<br><nobr>05. September 2020<\/nobr>", "05.09.2020", "05092020" ],
public DateTime end {get;set;}//":"2020-09-05T21:59:59.999999Z",
public DateTime runtime {get;set;}//":"2020-09-04T22:00:00.000000Z",
public Int32 upcoming {get;set;}//":14
public Int32 running {get;set;}//":87,
public Int64 termine {get;set;}//":16
}
public class Context
{
public List<Termine> termine{get;set;}
public Meta meta {get;set;}
}
So, your code will work with a few changes:
public static void Main(string[] args)
{
WebClient client = new WebClient()
{
Encoding = System.Text.Encoding.UTF8
};
string site = client.DownloadString("https://esel.at/api/termine/data?date=05.09.2020&selection=false");
Context ctx = JsonConvert.DeserializeObject<Context>(site);
ctx.termine.ForEach(Console.WriteLine);
}
Here is the link to the full solution where you can run and test.
https://dotnetfiddle.net/elq5Lv

Manipulating JSON data during Deserialization into class model

Is it possible to add two JSON fields together when deserializing?
For example:
public class root{
public List<cars> carList{get;set;}
}
public class cars{
public int HondaValue{get;set;}
public int fordValue{get;set;}
public int totalValue{get;set;}
}
JSON :
{
"carList":
{
"hondaValue":30,000,
"fordValue":40,000,
},
{
"hondaValue":55,000,
"fordValue":62,000,
},
{
"hondaValue":77,000,
"fordValue":65,000,
},
}
So can I get the sum of the hondaValue and fordValue for the total value in my class model during deserialization? Or do I have to set them to my model values after deserialization and add/set them to total?
You don't need to do a foreach just do it like this:
public struct Cars
{
public int HondaValue { get; set; }
public int FordValue { get; set; }
public int TotalValue
{
get
{
return HondaValue + FordValue;
}
}
}

Mapping 2 classes with same properties

I duplicated a Class1 in a Class2 with the same properties but not all ones. In my context, I have a Class1 obj (o1) initialised with values and I want to change some ones with values of a Class2 obj (o2) without losing the o1 data (values which aren't in o2). Manually, I need to reassignate o1 with values of o2 so I would like to find an automatic way like mapping the classes.
Classes:
public class Class1
{
public bool Property1;
public int Property2;
public string Property3;
public bool Property4;
public int Property5;
public string Property6;
public bool Property7;
public int Property8;
public string Property9;
public bool Property10;
public int Property11;
public string Property12;
public bool Property13;
public int Property14;
public string Property15;
public bool Property16;
public int Property17;
public string Property18;
public bool Property19;
public int Property20;
}
public class Class2
{
public bool Property1;
public int Property2;
public string Property3;
public bool Property7;
public int Property8;
public string Property9;
public bool Property10;
public int Property11;
public string Property12;
public bool Property13;
public int Property14;
public string Property15;
public bool Property16;
public int Property17;
public string Property18;
public bool Property19;
public int Property20;
public Class1 ToClass1()
{
return new Class1()
{
Property1 = Property1,
Property2 = Property2,
Property3 = Property3,
Property7 = Property7,
...
Property20 = Property20
};
}
}
If I do ToClass1(), I lose the values of Property4, Property5 and Property6 of the o1.
What I do now:
// o1 and o2 are initialised with values.
o1.Property1 = o2.Property1;
o1.Property2 = o2.Property2;
o1.Property3 = o2.Property3;
o1.Property7 = o2.Property7;
...
o1.Property20 = o2.Property20;
you need to use automapper and configure your mapping rule to ignore the properties you wont want to map.
Look at this link

how to generic type property

Is there a type like enum that would allow me to merge these variable into one
private string StringPropertie;
private int IntPropertie;
private float floatPropertie;
private DateTime DatetimePropertie;
private bool boolPropertie;
to something has follow.
private enumtype property
You can use structure
public struct MyStruct
{
public string StringPropertie;
public int IntPropertie;
public float floatPropertie;
public DateTime DatetimePropertie;
public bool boolPropertie;
}
public class MyClass
{
public MyClass()
{
MyStruct property ;
//...
string str = property.StringPropertie;
}
}

Categories

Resources