Serialización datos JSON en Windows Phone

Hay dos formatos principales para poder trabajar con información en la red, uno de ellos es XML, el segundo mucho mas reciente (y eficiente) es JSON, ambos tienen sus particularidades, la diferencia la pueden determinar dos factores esenciales, el primero y mas importante es si nuestro cliente nos da uno u otro formato simplemente debemos adaptarnos, el segundo factor es considerar la experiencia que tengamos para poder leer uno u otro elemento.

En este caso la idea es explicarte como serializar datos en formato JSON, que aunque es una tecnología un poco menos conocida, es mucho mas efectiva que XML.

Primero deberé comenzar por el inicio, explicar como es que se muestra un formato JSON, en la imagen siguiente tomé uno público y le di una forma un poco mas entendible, así que el resultado es como muestra el siguiente texto.

{
“created_at”:”Sat, 03 Mar 2012 03:19:09 +0000″,
“from_user”:”aminespinoza”,
“from_user_id”:56412327,
“from_user_id_str”:”56412327″,
“from_user_name”:”Amin Espinoza”,
“geo”:null,
“id”:175782334497435648,
“id_str”:”175782334497435648″,
“iso_language_code”:”es”,
“metadata”:{“result_type”:”recent”},
“profile_image_url”:”http:\/\/a0.twimg.com\/profile_images\/1563366776\/bcef476f-58f8-4ca3-9efb-6c250ae725f7_normal.png”,
“profile_image_url_https”:”https:\/\/si0.twimg.com\/profile_images\/1563366776\/bcef476f-58f8-4ca3-9efb-6c250ae725f7_normal.png”,
“source”:”<a href="http:\/\/www.tweetdeck.com" rel="nofollow">TweetDeck<\/a>”,
“text”:”El \u00faltimo trailer de la pel\u00edcula de Avenger agot\u00f3 la poca paciencia que ten\u00eda, ya quiero verla!!!!!”,
“to_user”:null,
“to_user_id”:null,
“to_user_id_str”:null,
“to_user_name”:null
},

Lo que al principio me llamó muchísimo la atención es que podría pasar por simple texto plano y que de esa forma lo podría interpretar, pero ¿Te imaginas la cantidad de métodos Split que deberías utilizar para lograr eso? Sería simplemente interminable y es por ello que hay una forma de serializar este formato de archivo.

Vayamos paso a paso, lo primero que debes saber ya entrando en materia es que utilizaremos el API de búsqueda de Twitter para obtener los resultados en formato JSON, para ello, utilizaremos la siguiente URL.

http://search.twitter.com/search.format

Con esta URL podremos ir obteniendo información por medio de una consulta, para este ejemplo utilizaré el parámetro “q”, dejando la URL de la siguiente manera.

http://search.twitter.com/search.json?q=aminespinoza

Y el resultado será lo siguiente.

resultadoJSON

Este será el resultado que utilizaremos, ahora crea un nuevo proyecto Windows Phone y en tu MainPage escribe el siguiente XAML reemplazando el Grid LayoutRoot

 

Como verás lo único que realmente te debe llamar la atención es el botón que utilizas para comenzarlo todo y un contenedor de tipo StackPanel que servirá para guardar nuestros resultados.

Además de los controles que creamos para la página principal, igualmente debes crear un nuevo UserControl que te servirá para desplegar los resultados de tus datos, el XAML de tu control será el siguiente.

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Serializacion_JSON.VistaTweet"
d:DesignWidth="480" d:DesignHeight="800" Width="456" Height="100">
 
<Grid x:Name="LayoutRoot" Background="Transparent">
<Image x:Name="imgUsuario" HorizontalAlignment="Left" Margin="8,8,0,8" Width="80" Height="80"/>
<TextBlock x:Name="txtMensaje" Margin="92,10,8,10" TextWrapping="Wrap"/>
</Grid>
</UserControl>

Este control cuenta con dos propiedades que se reflejarán a nivel visual y tres que solo nos servirán de manejo de información.

private string texto;
private string urlImagen;
public string Fecha { get; set; }
public string Usuario { get; set; }
public string NombreReal { get; set; }
 
public string UrlImagen
{
get { return urlImagen; }
set
{
urlImagen = value;
imgUsuario.Source = new BitmapImage(new Uri(urlImagen));
}
}
 
public string Texto
{
get { return texto; }
set { texto = value; txtMensaje.Text = texto; }
}

La idea es sencilla, en base a tus resultados irás llamando una nueva instancia de este control y lo colocarás en el contenedor de la página principal. Para ello vamos a la parte mas importante hablando de la serialización de JSON, crea una nueva clase, y pero en esta ocasión será utilizada de una forma un tanto diferente a la que habitualmente estás acostumbrado a utilizar.

ACTUALIZACIÓN: Si deseas poder generar esta clase mas fácilmente te invito a ver este artículo.

namespace Serializacion_JSON
{
[DataContract]
public class Tweet
{
[DataMember(Name = "created_at")]
public string Fecha { get; set; }
[DataMember(Name = "from_user")]
public string Usuario { get; set; }
[DataMember(Name = "from_user_name")]
public string NombreReal { get; set; }
[DataMember(Name = "profile_image_url")]
public string UrlImagen { get; set; }
[DataMember(Name = "text")]
public string Texto { get; set; }
}
 
[DataContract]
public class Mensajes
{
[DataMember(Name = "results")]
public List&lt;Tweet&gt; Tuit { get; set; }
}
 
}

Como puedes ver, estarás creando dos clases adentro pero de tipo DataContract a las cuales podrás insertarles un DataMember, cada uno de estos DataMembers corresponderá a cada uno de los atributos que obtendrás de tu archivo JSON (claro, solo usa los que te interesen).

Clases

En el segundo DataMember utilizarás una lista de tipo Tweet que te permitirá recibir todos los elementos de la respuesta.

Ya habiendo terminado con esto, nos regresaremos a nuestro MainPage y ahí debes comenzar por el Event Handler para el click del botón.

private void btnLlamar_Click(object sender, System.Windows.RoutedEventArgs e)
{
clienteProxy = new WebClient();
clienteProxy.OpenReadCompleted += new OpenReadCompletedEventHandler(proxy_OpenReadCompleted);
clienteProxy.OpenReadAsync(new Uri("http://search.twitter.com/search.json?q=aminespinoza"));
}

Aquí la cosa es utilizar un WebClient para poder consultar y obtener la información que necesitas y utilizar un Event Handler para el evento OpenReadCompleted, ahí harás lo siguiente.

void proxy_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null && e.Result.Length > 0)
{
Stream resultado = e.Result;
DataContractJsonSerializer serializador = new DataContractJsonSerializer(typeof(Mensajes));
Mensajes valoresDevueltos = serializador.ReadObject(resultado) as Mensajes;
 
foreach (Tweet elemento in valoresDevueltos.Tuit)
{
VistaTweet nuevoMensaje = new VistaTweet();
nuevoMensaje.Texto = elemento.Texto;
nuevoMensaje.UrlImagen = elemento.UrlImagen;
nuevoMensaje.Fecha = elemento.Fecha;
nuevoMensaje.Usuario = elemento.Usuario;
nuevoMensaje.NombreReal = elemento.NombreReal;
nuevoMensaje.Tap += nuevoMensaje_Tap;
contTweets.Children.Add(nuevoMensaje);
}
 
}
else
{
MessageBox.Show("Error");
}
}

Como siempre y de manera cautelosa debes verificar que el resultado contenga información y esta esté libre de errores, para que no haya ningún problema. Ya pasando por eso, utilizando un stream para manejar la información podrás crear una nueva instancia de la clase DataContractJsonSerializer y darle un formato adecuado, en este caso será del tipo Mensajes que se encuentra en la clase que creaste antes. Luego debes utilizar esa misma clase para leer los objetos recibidos y por medio de un casteo darles el formato adecuado.

Por último un ciclo se encargara de que por cada elemento que nos resulte se creará una nueva instancia de tu control personalizado y se colocará dentro de tu contenedor.

ListaTweets

Es así de sencillo como podemos obtener un archivo JSON y de esa manera serializarlo para nuestros fines, en la aplicación de ejemplo, hay un poco mas de funcionalidad simulando una ventana adicional que obtiene muchos mas datos, te sugiero echarle un ojo para expandir un poco la funcionalidad.

Puedes descargar el código aquí.

14 Comments

  • Amparo
    2 abril, 2012 - 10:44 am | Permalink

    Buenas,
    en primer lugar decirte que me ha gustado mucho este artículo, sencillo y efectivo. Sólo me ha quedado una duda, el 2º DataMember dices que es para recibir los elementos de la respuesta, pero estos han de estar contenidos en un contenedor tal y como están en el ejemplo y si en un json hay más de un contenedor, se crean más DataMember y listo, ¿es correcto?, la duda la tengo cuando quiero obtener el valor de una variable de un json que no está en un contenedor, te paso un link para que veas a qué me refiero:
    http://us.battle.net/api/wow/item/18608
    ¿cómo puedo acceder a las variables: “name”, “description”, “icon”… por ejemplo?
    Muchísimas gracias y un saludo.

    • Amin
      2 abril, 2012 - 5:14 pm | Permalink

      Hola Amparo, ya tengo tu JSON, ya ví donde están tus características, pero lo encontré en dos lugares diferenctes, uno al inicio y otro como propiedades de “spell”, cual de los dos es el que estás buscando solucionar?

      • Amparo
        3 abril, 2012 - 9:08 am | Permalink

        Hola Amin,

        gracias por tu pronta respuesta 🙂
        me refiero a las del inicio.

        • Amin
          6 abril, 2012 - 5:19 am | Permalink

          Siento la demora Amparo, tienes correo!!!!

  • Amparo
    2 abril, 2012 - 10:49 am | Permalink

    Otra cosita más :), cuando dentro de una variable que está contenida en un listado, esta variable contiene otro listado, ¿cómo funciona entonces el tema?

    Gracias y perdona por hacer tantas preguntas.

    • Amin
      2 abril, 2012 - 5:15 pm | Permalink

      Ja ja ja ja tu pregunta lo que gustes, esa es la idea 😀

  • 29 enero, 2013 - 7:15 pm | Permalink

    Hola Amin! oye te quiero hacer una pregunta, tu sabes por que me manda un error( cuando presiono el botón invocar sale el mensaje de error) cuando ejecuto la aplicación con vs 2012? y con vs 2010 corre perfectamente!
    Saludos y gracias!!

  • 29 enero, 2013 - 7:54 pm | Permalink

    Este es el error que me manda https://www.dropbox.com/s/ermvqv7u0721ly5/error.jpg
    lo estuve probando ya en visual studio 2012 con diferentes emuladores y con el que tengo problemas es con el Emulator WVGA y sus variantes con los demas no tengo problemas 7.1, 7.8, ¿sera que este proyecto no es compatible con windows phone 8?

    • Amin Espinoza
      29 enero, 2013 - 9:48 pm | Permalink

      Mmmm ya veo tu error, no es que sea incompatible, primero dale una checada a tu emulador Windows Phone porque estoy casi seguro de que no tienes acceso a datos. Entra a tu navegador y checa que puedas ir a un sitio, de ser así solo debes ver que primero tenga acceso a datos. Me avisas que tal

      • 30 enero, 2013 - 5:42 am | Permalink

        ya se soluciono :)! no se porque pero tener varias conexiones de red virtuales me ha traído muchos problemas, gracias!

        • Amin Espinoza
          31 enero, 2013 - 4:05 pm | Permalink

          Que bueno que todo estuvo en orden. Saludos!!

  • 31 enero, 2013 - 10:55 pm | Permalink

    Hola de nuevo Amin!
    oye como podría agregar a este ejemplo un progressbar de modo indeterminado? ,eh leido que se necesita un BackGroundWorker pero ya tengo varios dolores de cabeza con este tema, saludos!

  • Juan
    21 febrero, 2014 - 1:46 am | Permalink

    Hola!!
    Me pareció muy bueno tu post, pero tengo una duda, ya con la versión de twitter api 1.1 cambio la estructura del JSON y me parece algo súper complicado, lo que quiero hacer es ser capaz de identificar un link dentro de un tweet y desplegar el tweet en un TextBlock y cuando el usuario le de click o tap lo lleve a link que esta dentro del tweet.
    ¿Sabes como se puede hacer eso?

    Gracias y saludos.

  • Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    This blog is kept spam free by WP-SpamFree.