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.
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<Tweet> 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).
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.
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.
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.
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?
Hola Amin,
gracias por tu pronta respuesta 🙂
me refiero a las del inicio.
Siento la demora Amparo, tienes correo!!!!
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.
Ja ja ja ja tu pregunta lo que gustes, esa es la idea 😀
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!!
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?
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
ya se soluciono :)! no se porque pero tener varias conexiones de red virtuales me ha traído muchos problemas, gracias!
Que bueno que todo estuvo en orden. Saludos!!
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!
Enviame por favor un correo a amin.espinoza@gmail.com y te mando una utilería que te puede servir.
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.