Cómo consumir y deserializar JSON en Windows Phone
Muchos webservices que pueden encontrar en internet devuelven información en formato JSON. Haremos un ejercicio, descargando información del clima desde OpenWeatherMap.
Al descargar la información de Santiago de Chile, nos encontramos con lo siguiente:
http://api.openweathermap.org/data/2.5/weather?q=Santiago,CL
{"coord":{"lon":-70.65,"lat":-33.46},"sys":{"message":0.1043,"country":"CL","sunrise":1388741909,"sunset":1388793378},"weather":[{"id":800,"main":"Clear","description":"Sky is Clear","icon":"01d"}],"base":"cmc stations","main":{"temp":301.15,"pressure":1014,"humidity":23,"temp_min":301.15,"temp_max":301.15},"wind":{"speed":3.6,"deg":170,"var_beg":120,"var_end":230},"clouds":{"all":0},"dt":1388764800,"id":3871336,"name":"Santiago","cod":200}
Para los que no hayan trabajado con JSON antes, JSON es una notación de contenido y estructura de objetos. Para ver la estructura más gráficamente, siempre uso este sitio: Online JSON Viewer. Simplemente peguen el string JSON en la pestaña Text y luego vayan a Viewer para conocer la estructura y los valores:
Ahora que ya tienen una idea de cómo es la estructura, hay que imaginarse cómo podríamos consumir este string y obtener esa estructura como un objeto en C#, idealmente con la menor cantidad de código posible. Este proceso formalmente se llama deserialización.
Acá podemos usar dos caminos: uno que es compatible con Windows Phone 7 y otro que no.
Prerequisitos
En NuGet, instalar JSON.NET y HttpClient. Para Windows Phone 7, además debes instalar Async.
Para Windows Phone 7 y 8
Tendremos que crear clases que representen la estructura de nuestro objeto JSON. Si se fijan en el ejemplo, quedaría algo así:
public class Coord { public float lon; public float lat; } public class Sys { public float message; public string country; public long sunrise; public long sunset; } public class Weather { public int id; public string main; public string description; public string icon; } public class Main { public float temp; public int pressure; public int humidity; public float temp_min; public float temp_max; } public class Wind { public float speed; public int deg; public int var_beg; public int var_end; } public class Clouds { public int all; } public class Salida { public Coord coord; public Sys sys; public List<Weather> weather; [JsonProperty(PropertyName = "base")] // "base" es un keyword en C# public string base; public Main main; public Wind wind; public Clouds clouds; public long dt; public int id; public string name; public int cod; }
Luego, para obtener el objeto a partir del string, hacemos algo así:
var cl = new HttpClient(); var res = await cl.GetAsync(new Uri("http://api.openweathermap.org/data/2.5/weather?q=Santiago,CL")); string json = await res.Content.ReadAsStringAsync(); var obj = JsonConvert.DeserializeObject<Salida>(json); var desc = obj.weather[0].description;
Importante destacar que si un elemento del JSON no existe en la clase, esto no producirá error. Asimismo, si existen atributos en la clase que no existan en el JSON, se llenarán con su valor default(type).
Para Windows Phone 8
Es mucho más fácil pero también más “peligroso”. En .NET 4.5 tenemos el keyword “dynamic” que nos permite hacer algo como esto, sin tener que definir tantas clases:
var cl = new HttpClient(); var res = await cl.GetAsync(new Uri("http://api.openweathermap.org/data/2.5/weather?q=Santiago,CL")); string json = await res.Content.ReadAsStringAsync(); dynamic obj = JsonConvert.DeserializeObject(json); var desc = obj.weather[0].description; MessageBox.Show(desc.ToString());
Lo que acá hay que comprender es que el compilador no tiene idea de la estructura de “obj”, hasta llegar a tiempo de ejecución, donde “obj.weather[0].description” se interpreta y evalúa. Si el string JSON por algún motivo no tiene el campo “description” va a lanzar una excepción.
Hola, interesante tu post. Una consulta obj.weather[0].description; que seria?¿ Porque me lanza una excepcion, como bien remarcas, y no se como solucionarlo…
En este caso, “obj” representa al JSON tal cual como se ve en la primera imagen. Es decir, obj va a tener elementos de nombre “coord”, “sys”, “weather”, etcétera.
Si te fijas, el elemento weather es un array (está representado con corchetes), por lo que puedes usar la notación weather[0] para el primer elemento, weather[1] para el segundo, etcétera.
Me imagino que si se te está lanzando una excepción, es porque el array weather no existe o está vacío, por lo que ni siquiera tiene un elemento.