I am working on a market data processor. I am currently ingesting responses from the Bureau of Labor Statistics. I have just hit an interesting snag that I am not 100% sure how to get around.
I am using Newtonsoft to deserialize my objects and in the Calculations portion of the response it looks like this
"calculations": {
"net_changes": {
"1": "133",
"3": "220",
"6": "1985",
"12": "2949"
},
"pct_changes": {
"1": "0.1",
"3": "0.1",
"6": "1.2",
"12": "1.8"
}
}
So I created my objects like this
public class Calculations
{
public Net_Changes net_changes { get; set; }
public Pct_Changes pct_changes { get; set; }
}
public class Net_Changes
{
public string _1 { get; set; }
public string _3 { get; set; }
public string _6 { get; set; }
public string _12 { get; set; }
}
public class Pct_Changes
{
public string _1 { get; set; }
public string _3 { get; set; }
public string _6 { get; set; }
public string _12 { get; set; }
}
However when I go to deserialize the root object everything seems fine until I look at the calculations portion of the object and it is null. Looking at postman data is definitely coming back. Is it possible for me to use NewtonSoft to deserialize this object with it mapping "1" to _1 (pun intended) ?
Resources I accessed
this one seemed like it might have been the ticket. Maybe I didn't understand it correctly.
Deserialize JSON with numbers as property names
Thanks for any and all help!
Adam
you have to fix your data structure by adding an extra class.
The easiest way is to add property names
Calculations calculations = JsonConvert.DeserializeObject<Calculations>(json);
public class Calculations
{
public Changes calculations { get; set; }
}
public class Changes
{
public Net_Changes net_changes { get; set; }
public Pct_Changes pct_changes { get; set; }
}
public class Net_Changes
{
[JsonProperty("1")]
public string _1 { get; set; }
[JsonProperty("3")]
public string _3 { get; set; }
// and so on
}
public class Pct_Changes
{
[JsonProperty("1")]
public string _1 { get; set; }
[JsonProperty("3")]
public string _3 { get; set; }
//and so on
}
but if for some reasons you can not add property names, the second way (more messy) is to use custom IContractResolver
var settings = new JsonSerializerSettings
{
ContractResolver = new NumberNameContractResolver()
};
Calculations calculations = JsonConvert.DeserializeObject<Calculations>(json,settings);
public class NumberNameContractResolver : DefaultContractResolver
{
public static readonly NumberNameContractResolver Instance = new NumberNameContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyName.StartsWith("_"))
property.PropertyName = property.PropertyName.Substring(1);
return property;
}
}
the third way is to use this code that is quite messy too
var jObj = JObject.Parse(json);
foreach (var jO in jObj.DescendantsAndSelf())
{
if (jO is JObject obj)
foreach (var prop in obj.Properties().ToList())
if (prop.Value.Type != JTokenType.Object)
{
prop.AddAfterSelf(new JProperty("_" + prop.Name, prop.Value));
prop.Remove();
}
}
Calculations calculations = jObj.ToObject<Calculations>()