Reputation: 14024
The JSON looks like this
{
"123": {
"Type": "IN",
"OUTAgentMACID": "00-14-22-01-23-45",
"PlateNumber": {
"Image": "/poll/data/date0/img.png",
"Number": "ABC1234",
"TimeStamp": 5901291
}
},
"124": {
"Type": "OUT",
"OUTAgentMACID": "00-14-22-01-31-45",
"PlateNumber": {
"Image": "/poll/data/date0/img.png",
"Number": "ABC1234",
"TimeStamp": 5991291
}
},
"125": {
"Type": "IN",
"INAgentMACID": "00-14-22-01-63-45",
"PlateNumber": {
"Image": "/poll/data/date1/img.png",
"Number": "ABC1234",
"TimeStamp": 6001239
}
}
}
The probable class structure is
public class PlateNumber
{
public string Image { get; set; }
public string Number { get; set; }
public int TimeStamp { get; set; }
}
public class Activity
{
public string Type { get; set; }
public string AgentMACID { get; set; }
public PlateNumber PlateNumber { get; set; }
}
public class SessionActivity
{
public Dictionary<int, Activity> Activities { get; set; }
}
Helper looks like this
public class helpers : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }
public helpers()
{
PropertyMappings = new Dictionary<string, string>
{
{"INAgentMACID", "AgentMACID"},
{"OUTAgentMACID", "AgentMACID"},
};
}
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}
Now when I try to deserializing it like this
var settings = new JsonSerializerSettings();
settings.ContractResolver = new helpers();
var activities = JsonConvert.DeserializeObject<SessionActivity>("Some.json"), settings);
the activities
is null.
The Problem is AgentMACID
Since the JSON have either OUTAgentMACID
or INAgentMACID
depending on the Type
Please help me design the class for this JSON.
Upvotes: 1
Views: 491
Reputation: 673
1 - Deserialize a Dictionary from JSON
Based on your json object :
{
"123": {
"Type": "IN",
"OUTAgentMACID": "00-14-22-01-23-45",
"PlateNumber": {
"Image": "/poll/data/date0/img.png",
"Number": "ABC1234",
"TimeStamp": 5901291
}
},
"124": {
"Type": "OUT",
"OUTAgentMACID": "00-14-22-01-31-45",
"PlateNumber": {
"Image": "/poll/data/date0/img.png",
"Number": "ABC1234",
"TimeStamp": 5991291
}
},
"125": {
"Type": "IN",
"INAgentMACID": "00-14-22-01-63-45",
"PlateNumber": {
"Image": "/poll/data/date1/img.png",
"Number": "ABC1234",
"TimeStamp": 6001239
}
}
}
You can deserialize a dictionary using :
var activities = JsonConvert.DeserializeObject<Dictionary<int, Activity>>("Some.json"), settings);
2.1 - Manage multiple json property names in one C# property
For your second issue you can define your Activity
class like this :
public class Activity
{
public string Type { get; set; }
public string AgentMACID { get; set; }
// Optional: you can rename your property with this property attribute
// [JsonProperty("INAgentMACID")]
public string INAgentMACID { set { AgentMACID = value; } }
// Optional: you can rename your property with this property attribute
// [JsonProperty("OUTAgentMACID")]
public string OUTAgentMACID { set { AgentMACID = value; } }
public PlateNumber PlateNumber { get; set; }
}
2.2 - You can also inherit DefaultContractResolver as you were doing :
public class RenamePropertySerializerContractResolver : DefaultContractResolver
{
private readonly Dictionary<Type, HashSet<string>> _ignores;
private readonly Dictionary<Type, Dictionary<string, string>> _renames;
public RenamePropertySerializerContractResolver()
{
_renames = new Dictionary<Type, Dictionary<string, string>>();
}
public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
{
if (!_renames.ContainsKey(type))
_renames[type] = new Dictionary<string, string>();
_renames[type][propertyName] = newJsonPropertyName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
property.PropertyName = newJsonPropertyName;
return property;
}
private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
{
Dictionary<string, string> renames;
if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
{
newJsonPropertyName = null;
return false;
}
return true;
}
}
And finally use you new ContractResolver :
var jsonResolver = new RenamePropertySerializerContractResolver();
jsonResolver.RenameProperty(typeof(Activity), "INAgentMACID", "AgentMACID");
jsonResolver.RenameProperty(typeof(Activity), "OUTAgentMACID", "AgentMACID");
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;
var activities = JsonConvert.DeserializeObject<IDictionary<int, Activity>>(json, serializerSettings);
Upvotes: 1
Reputation: 1341
I think it's not directly possible that you have one Property, which represents two Properties of the json- (as I've read here Make JsonPropertyAttribute allow multiple usages on same property)
What I undertsand from this post, you would be forced to have another property, which just "forwards" the value to the one you want.
example:
public class Activity
{
public string Type { get; set; }
public string AgentMACID { get; set; }
private string AgentMACID2 { set { AgentMACID = value; } } // used to map the other field of json
public PlateNumber PlateNumber { get; set; }
}
in the Contract Resolver you have to mape vias versa as you did. With the second field I added, it might looks as this:
PropertyMappings = new Dictionary<string, string>
{
{"AgentMACID","OUTAgentMACID"},
{"AgentMACID2","INAgentMACID"}
};
And deserialize by this:
var activities = JsonConvert.DeserializeObject<Dictionary<int, Activity>>("json content", settings);
Upvotes: 1