Reputation: 21
Normally when I use API's and get a Json string back I simply make a class to suit the string and populate that class using newton JsonConvert.DeserializeObject.
However I now have a Json string which 1 of the fields does not have a name.
{
"attacks": {
"114862720": {
"code": "115dc2b990153c41c33d519b26cc302a",
"timestamp_started": 1596782220,
"timestamp_ended": 1596782226,
"attacker_id": 580816,
"attacker_name": "chedders",
"attacker_faction": 32585,
"attacker_factionname": "Heart of a Pirate",
"defender_id": 65306,
"defender_name": "-Clansdancer",
"defender_faction": 0,
"defender_factionname": null,
"result": "Attacked",
"stealthed": 0,
"respect_gain": 4.14,
"chain": 3,
"modifiers": {
"fairFight": 3,
"war": 1,
"retaliation": 1,
"groupAttack": 1,
"overseas": 1,
"chainBonus": 1
}
},
"114862829": {
"code": "8bf08c8ceb9b72f05f40235310cd822e",
"timestamp_started": 1596782339,
"timestamp_ended": 1596782344,
"attacker_id": 580816,
"attacker_name": "chedders",
"attacker_faction": 32585,
"attacker_factionname": "Heart of a Pirate",
"defender_id": 964979,
"defender_name": "brko21",
"defender_faction": 0,
"defender_factionname": null,
"result": "Attacked",
"stealthed": 0,
"respect_gain": 4.11,
"chain": 4,
"modifiers": {
"fairFight": 3,
"war": 1,
"retaliation": 1,
"groupAttack": 1,
"overseas": 1,
"chainBonus": 1
}
}
}
}
After attacks is an ID which is unique to each entry.so building a class for this as I normally would just wont work as the ID is unknown.
Any pointers on how to deserialise this string would be most welcome.
Upvotes: 2
Views: 1246
Reputation: 1101
Try this json converter.
class AttacksConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Attacks[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject attacks = serializer.Deserialize<JObject>(reader);
Dictionary<string, AttackDetails> result = new Dictionary<string, AttackDetails>();
foreach (JProperty property in attacks.Properties())
{
string attackKey = property.Name;
Attacks attackValue = property.Value.ToObject<Attacks>();
result.Add(attackKey, new AttackDetails()
{
Code = attackValue.Code
});
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
The full code can be found here: https://github.com/tmutton/StackOverflowQuestion63544325
Upvotes: 1
Reputation: 1433
This would deserialise to a Dictionary<string, Attack>
. Where Attack is a type that you define with all of the properties within each object, in the JSON document.
This example assumes you're using NewtonSofts JSON library:
var attacks = JsonConvert.DeserializeObject<Dictionary<string, Attack>>(jsonString);
public class Attack {
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("timestamp_started")]
public long TimestampStarted { get; set; }
[JsonProperty("timestamp_ended")]
public long TimestampEnded { get; set; }
[JsonProperty("attacker_id")]
public int AttackerId { get; set; }
[JsonProperty("attacker_name")]
public string AttackerName { get; set; }
[JsonProperty("attacker_faction")]
public int AttackerFaction { get; set; }
[JsonProperty("attacker_factionname")]
public string AttackerFactionName { get; set; }
[JsonProperty("defender_id")]
public int DefenderId { get; set; }
[JsonProperty("defender_name")]
public string DefenderName { get; set; }
[JsonProperty("defender_faction")]
public int DefenderFaction { get; set; }
[JsonProperty("defender_factionname")]
public string DefenderFactionName { get; set; }
[JsonProperty("result")]
public string Result { get; set; }
[JsonProperty("stealthed")]
public int Stealthed { get; set; }
[JsonProperty("respect_gain")]
public decimal RespectGain { get; set; }
[JsonProperty("chain")]
public int Chain { get; set; }
[JsonProperty("modifiers")]
public Dictionary<string, int> Modifiers { get; set; }
}
This results in a collection of identifiers against a strongly typed field set.
var allAttacksByFaction = attacks.Where(x => x.Value.AttackerFaction == 1234);
var singleAttack = attacks.Single(x => x.Key == "<value of attack identifier>");
Upvotes: 1
Reputation: 26352
You can use the [JsonExtensionData]
property.
Here's the official example:
public class DirectoryAccount
{
// normal deserialization
public string DisplayName { get; set; }
// these properties are set in OnDeserialized
public string UserName { get; set; }
public string Domain { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> _additionalData;
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
// SAMAccountName is not deserialized to any property
// and so it is added to the extension data dictionary
string samAccountName = (string)_additionalData["SAMAccountName"];
Domain = samAccountName.Split('\\')[0];
UserName = samAccountName.Split('\\')[1];
}
public DirectoryAccount()
{
_additionalData = new Dictionary<string, JToken>();
}
}
So in your OnDeserializing
method, you can get the values from the dictionary and add them to a proper field/cast them to a list of objects, etc.
Upvotes: 1