Actualmente estoy tratando de obtener datos de una API externa. Los datos que recibo se parecen a los que se muestran a continuación. (Solo una maqueta; no espere que los valores tengan ningún sentido. Es solo para ilustrar qué tipo de datos obtengo).
{ "user": [ { "key": "12345678", "data": [ { "id": "Name", "string": "Bob" }, { "id": "ElapsedTimeSinceLastMessage", "timestamp": 1618233964000 }, { "id": "Age", "number": 27 } ] } ] }Realmente no sé cómo debería deserializar este JSON.
Las clases que estoy usando para deserializar en este momento se ven así:
public class User { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("data")] public List<DataEntry> DataEntries { get; set; } } public class DataEntry { [JsonProperty("id")] public string Id { get; set; } public Type Value { get; set; } } Y no sé qué debo configurar para deserializar el Value dentro de DataEntry . ¿Quizás alguien pueda guiarme en la dirección correcta?
Un ángulo de ataque sería con Diccionarios:
public class WithUser { public List<User> User { get; set; } } public class User { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("data")] public List<Dictionary<string,object>> DataEntries { get; set; } }La extracción es un poco dolorosa pero posible:
public static void Main() { var json = File.ReadAllText("Example.json"); var x = JsonConvert.DeserializeObject<WithUser>(json); var user = x.User.Single(); var age = Extract<long>(user, "Age"); var name = Extract<string>(user, "Name"); var elapsedTimeSinceLastMessage = TimeSpan.FromTicks(Extract<long>(user, "ElapsedTimeSinceLastMessage")); } public static T Extract<T>(User user, string name) { var o = user.DataEntries .SingleOrDefault(d => (string)d["id"] == name) // Find the one with age .SingleOrDefault(kvp => kvp.Key != "id") // Find the not 'id' value .Value; // Take the value return (T)o; }La parte de Data de este JSON es realmente solo un Dictionary<string, object> disfrazado. Puede usar un JsonConverter personalizado para transformar la lista de pares de ID/valor en ese formato para facilitar su uso.
Primero, defina estas clases:
class RootObject { [JsonProperty("user")] public List<User> Users { get; set; } } class User { public string Key { get; set; } [JsonConverter(typeof(CustomDataConverter))] public Dictionary<string, object> Data { get; set; } }A continuación, defina el convertidor:
class CustomDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Dictionary<string, object>); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return JToken.Load(reader) .Children<JObject>() .ToDictionary(jo => (string)jo["id"], jo => jo.Properties() .Where(jp => jp.Name != "id" && jp.Value is JValue) .Select(jp => ((JValue)jp.Value).Value) .FirstOrDefault()); } public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }Luego puede deserializar y volcar los datos de esta manera:
var root = JsonConvert.DeserializeObject<RootObject>(json); foreach (User user in root.Users) { Console.WriteLine("User Key: " + user.Key); foreach (var kvp in user.Data) { Console.WriteLine(kvp.Key + ": " + kvp.Value); } }Aquí hay una demostración funcional: https://dotnetfiddle.net/GIT4dl
El problema principal está en los modelos que ha creado.
En primer lugar, en base al JSON, necesita otra clase que contenga una lista de Usuarios.
public class ResultClass { public List<User> User { get; set; } }Después de eso, debido a que el segundo objeto de la propiedad de datos no tiene un nombre constante, no podemos especificarle un nombre constante (como valor). Deberíamos definir la propiedad de datos como un objeto. Así que la clase de usuario debería ser así:
public class User { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("data")] public List<object> DataEntries { get; set; } }Al final, en el controlador, debe deserializar la clase ResultJson:
var result = JsonConvert.DeserializeObject<ResultClass>(jsonTxt);