I have the below rather simple build of classes, they represent a model, kindly note the linked classes (initialization included in appropriate instance constructors of each one):
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public DataClass()
{
part = new PartClass();
member = new MemberClass();
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
public MemberClass()
{ side = new SideClass(); }
}
public class SideClass : IMPropertyAsStringSettable
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
public SideClass()
{ }
}
My problem is rather straightforward, however, the complication is on the implementation: I am creating a class dynamically, expando, and I read a JSON which, sometimes, is equivalent one-on-one with the DataClass hierarchy, like:
{
"num": "3",
"code": "some sort of string",
"part": {
"seriesNum": "3",
"seriesCode": "sample"
},
"member": {
"versionNum": "1.5",
"side": {
"firstDetail": "aFirst",
"secondDetail": "aSecond",
"include": "true"
}
}
}
and sometimes, only a few values are equivalent (being a sub-set of DataClass is not an error, if there is an unknown tag in JSON, this is an error - like for example, find "age": "18" in JSON, because DataClass does not contain anywhere an 'age' property etc.), like for example:
{
"num": "9",
"part": {
"seriesNum": "3",
},
"member": {
"versionNum": "1.5",
"side": {
"include": "true"
}
}
}
As said, I don't care if a property - or a whole tree of properties - is missing from the JSON compared to the DataClass.
My problem is, how to read the JSON and assign properties and values in expando, while checking that both the hierarchy as well as the property name are correct.
Could you help me please with this?
Related
I have JSON which looks something like this (external JSON beyond my control):
[
{
"currencies": {
"KGS": {
"name": "Kyrgyzstani som",
"symbol": "с"
}
}
},
{
"currencies": {
"SOS": {
"name": "Somali shilling",
"symbol": "Sh"
}
}
}
]
And I have a set of classes which I would like this JSON deserialized into
public class ParentClass
{
public OuterClass Currencies { get; set; }
}
public class OuterClass
{
//Inner property below needs to map to these changing prop names: "KGS", "SOS"
public InnerClass Inner { get; set; }
}
public class InnerClass
{
public string Name { get; set; }
public string Symbol { get; set; }
}
And Lastly, when I try to deserialize:
JsonConvert.DeserializeObject<IList<ParentClass>>(responseBody.Content);
It's not deserializing properly, because the it cannot map varying Property names to "Inner". Is there a way to handle this scenario?
Newtonsoft didn't seem to have any problem with it..
public partial class Blah
{
[JsonProperty("currencies")]
public Dictionary<string, Currency> Currencies { get; set; }
}
public partial class Currency
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("symbol")]
public string Symbol { get; set; }
}
And
var blah = JsonConvert.DeserializeObject<Blah[]>(jsonString);
..though it's probably worth noting I think you have your parent and outer the wrong way round if this json is just a fragment..
I'm having difficulties figuring out how to deserialize a json, that has a dynamic property (for example - UserRequest::567) the property name can be any value and the UserRequest object contains other json properties that are of interest to me
I tired writing a class and I don't know what to do with that property. What are the best practices for coping with a problem like this?
{
"objects": {
"UserRequest::567": {
"code": 0,
"message": "created",
"class": "UserRequest",
"key": "567",
"fields": {
"ref": "R-000567",
"org_id": "4"
}
}
}
}
The question is what are the best practices to read through this kind of a json string?
Thank you
To Deserialize this using Newtonsoft.Json, here are the classes:
public class CreateRequest
{
public long code { get;set; }
public string message { get; set; }
[JsonProperty("class")]
public string class1 { get; set; }
public string key { get; set; }
public Fields fields { get; set; }
}
public class Fields
{
[JsonProperty("ref")]
public string refe { get; set; }
public string org_id { get; set; }
}
public class Root
{
public Dictionary<string, CreateRequest> objects { get; set; }
//The 'string' key in the dictionary is the 'UserRequest::567'
}
Then to Deserialize use:
var x = Newtonsoft.Json.JsonConvert.DeserializeObject<Root>(jsonObject).objects.Values;
I am having trouble deserializing json I have that has an # symbol at the beginning of a lot of the property names. It is a lot of json so I don't know if just removing all # from the json is safe or if I would lose some valuable information in the values associated with properties.
I tried using a [JsonProperty("#fontName")], for example, but that didn't work (the C# object did not adopt the value I see in the JSON; it was null instead).
internal static RootObject MyMethod(string json)
{
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
return rootObject;
}
Here is a snippet of the json I'm dealing with:
{
"document": {
"page": [
{
"#index": "0",
"row": [
{
"column": [
{
"text": ""
},
{
"text": {
"#fontName": "Times New Roman",
"#fontSize": "8.0",
"#x": "133",
"#y": "14",
"#width": "71",
"#height": "8",
"#text": "FINAL STATEMENT"
}
...
Here is an example of what I want to deserialize into:
public class Column
{
[JsonProperty("#fontName")]
public string fontName { get; set; }
public object text { get; set; }
}
public class Row
{
public List<Column> column { get; set; }
public string text { get; set; }
}
public class Page
{
public string index { get; set; }
public List<Row> row { get; set; }
public string text { get; set; }
}
public class Document
{
public List<Page> page { get; set; }
}
public class RootObject
{
public Document document { get; set; }
}
From what I see you miss one of your properties index property of your Page object.
Write it this way [JsonProperty(PropertyName ="#index")] it is better to understand. Also we don't see the definition of fontName, fontSize, x, y and so on, in separate Text class. For some reason you wrote it as just as object.
public class Text
{
[JsonProperty(PropertyName ="#fontName")]
public string FontName {get; set;}
[JsonProperty(PropertyName ="#fontSize")]
public string FontSize {get; set;}
[JsonProperty(PropertyName ="#text")]
public string TextResult{get; set;}
//other objects
}
public class Column
{
public List<Text> text { get; set; }
}
hotel_pricesURL = string_builder.ToString();
RootobjectOne robjectOne = JsonConvert.DeserializeObject<RootobjectOne>(hotel_pricesURL);
List<OneStar> one_star_list = new List<OneStar>();
var check = robjectOne.onestar;
foreach(var items in check)
{
}
Including RootobjectOne class:
public class RootobjectOne
{
[JsonProperty("OneStar")]
public OneStar onestar { get; set; }
[JsonProperty("TwoStar")]
public TwoStar twostar { get; set; }
[JsonProperty("ThreeStar")]
public ThreeStar threestar { get; set; }
[JsonProperty("FourStar")]
public FourStar fourstar { get; set; }
[JsonProperty("FiveStar")]
public FiveStar fivestar { get; set; }
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
}
public class OneStar
{
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
[JsonProperty("median")]
public string median { get; set; }
[JsonProperty("lowest")]
public string lowest { get; set; }
[JsonProperty("value")]
public string value { get; set; }
//public string
}
**this is the response from the web service**
{
"5 star": {
"median": "134.04",
"lowest": "83.57",
"value": "134.04"
},
"1 star": {
"median": "28.86",
"lowest": "28.86",
"value": "28.86"
},
"4 star": {
"median": "76.35",
"lowest": "36.71",
"value": "76.35"
},
"2 star": {
"median": "24.78",
"lowest": "20.42",
"value": "24.78"
},
"3 star": {
"median": "37.65",
"lowest": "20.33",
"value": "37.65"
}
}
I am getting an error stating
Unable to cast object of type 'OneStar' to type'System.Collections.IEnumerator'
Why? And how do I solve this?
First, your class is implementing, but not inheriting the IEnumerable interface, so it is still not seen as a collection.
Second, even if you inherit it, you have no collections in OneStar and nothing to enumerate.
Third, all those Json flags are not necessary as you are just redefining the defaults that are already set.
Solution
You need an additional "wrapper" class that is your collection, or just omit your custom implementation of an enumerable collection (as it does not appear from your code that you need it) and just define the property that contains the class as a collection:
public class RootobjectOne
{
public List<OneStar> onestar { get; set; }
public List<TwoStar> twostar { get; set; }
public List<ThreeStar> threestar { get; set; }
public List<FourStar> fourstar { get; set; }
public List<FiveStar> fivestar { get; set; }
}
I have a JSON class structure like this from a third party API (only the problem part shown):
"template": {
"name": "MovieTemplate",
"ruleName": "Movie Template",
"zones": {
"Products": {
"type": "Record",
"name": "Products",
"content": "www.imagescloudsite.com/blahblah.gif"
"records": [ … ]
},
"URL": {
"type":"DVD",
"name":"Bundle"
"content": "www.imagescloudsite.com/blahblah.gif"
}
}
}
The "zones" property can contain many properties "Products","URL","Superman","Descartes",etc...
But, I do not know which ones and how many will be there, because these are added by our content guys in a special control panel. Newtonsoft Deserializer complains because I have a model like this and it clearly does not capture the zone name like 'Products' and 'URL':
public class Zone
{
public string Type { get; set; }
public string Name { get; set; }
public string Content { get; set; }
}
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public List<Zone> Zones { get; set; }
}
Any ideas on how I can capture the zone names using NewtonSoft?
Thanks.
Turn your Zone property to a dictionary since you don't know the keys in before hand, but do know their content structure.
Like so
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public Dictionary<string,Zone> Zones { get; set; }
}
What if you changed the Template class to the following:
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public Dictionary<string, Zone> Zones { get; set; }
}
You could then access the name via the key of the entry.
Use of dynamic would be a good bet
dynamic d = Newtonsoft.Json.Linq.JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}");