Ejemplo practico: Mostrando el horóscopo desde una fuente externa con HttpWebRequest, HttpWebResponse, Linq y Ajax

De un tiempo a esta parte y sobre todo desde que se empezó a hablar de la web 2.0, muchos sitios exponen su información para que se pueda explotar desde diferentes aplicaciones así que en este post vamos a ver cómo obtener información de una fuente de datos externa por medio de la clase HttpWebRequest y HttpWebResponse perteneciente a System.Net, posteriormente la trataremos con Linq To Xml y para finalizar, crearemos una interfaz rica con Ajax.

Para que podamos explotar la info de un sitio web, lo primero que vamos a necesitar es saber qué es lo que vamos a explotar. Nosotros, vamos a usar un XML que expone Terra para mostrar el horóscopo.

Lo primero que vamos a necesitar, es una entidad para ir manejando los datos, a esta entidad, le he llamado HoroscopeInfo, y tiene este aspecto:

public class HoroscopeInfo
{
public string Signo { get; set; }
public string Descripcion { get; set; }
}

Usando HttpWebRequest y HttpWebResponse para explotar información externa a nuestra aplicación.

La entidad ya la tenemos, pues ahora veamos qué información nos tenemos que traer. El horóscopo de Terra, está expuesto en esta url y nos lo vamos a traer a nuestro sitio por medio HttpWebRequest y HttpWebResponse.

HttpWebRequest proporciona una implementación específica para el protocolo Http de la clase WebRequest (ya que HttpWebRequest hereda de WebRequest como su nombre indica ;-)) así pues, HttpWebRequest admite las propiedades y métodos definidos para WebRequest, y sus propiedades y métodos adicionales nos permiten interactuar con el protocolo Http directamente.

Para instanciar nuestra WebRequest, usaremos el método Create, al cual pasándole una Url, ya nos devuelve el objeto HttpWebRequest creado y posteriormente usando el método GetResponse, nos traeremos el recurso al que estamos accediendo (en este caso el horóscopo). GetResponse, realiza una solicitud sincrónica y devuelve un objeto HttpWebResponse con la respuesta.

HttpWebResponse proporciona una implementación específica para el protocolo Http de la clase WebResponse (HttpWebResponse hereda de WebResponse).

Una vez tenemos el response, ya lo único que nos queda es tratarlo para devolver lo que esperamos. En nuestro caso vamos a devolver un XElement para poder operar posteriormente con Linq. El código sería el siguiente:

private XElement getXmlHoroscope()
{
string response = string.Empty;
WebRequest objRequest = HttpWebRequest.Create(ConfigurationManager.AppSettings[DomainConstants.URL_HOROSCOPE_CONFIG_ENTRY]);
WebResponse objResponse = objRequest.GetResponse();
using (StreamReader sr = new StreamReader(objResponse.GetResponseStream(), Encoding.GetEncoding("iso-8859-1")))
{
response = sr.ReadToEnd();
sr.Close();
}
return XElement.Parse(response);
}

Linq para tratar los datos

Linq como ya vimos, nos va a permitir a permitir obtener una colección de datos desde el XML (esto se conoce por Linq To Xml) donde tenemos almacenada la info del horóscopo.

Veamos el código necesario:

from horoscopeNode in horoscopeInfo.Descendants(DomainConstants.ZODIACO)
select new HoroscopeInfo
{
Signo = (string)horoscopeNode.Attribute(DomainConstants.SIGNO),
Descripcion = horoscopeNode.Element(DomainConstants.PREDICCION).Value
}

Bien con la sentencia anterior, lo que conseguimos es iterar por una colección que nos devuelve la sentencia .Descendants(“xName”) y por cada ítem creamos un nuevo HoroscopeInfo, devolviendo al final un IEnumerable.

Para finalizar, como quiero devolver una lista de genéricos, solo tengo que crearla y pasarle el IEnumerable al constructor. Y quedaría así:

public List GetHoroscope()
{
XElement horoscopeInfo = getXmlHoroscope();
return new List
(from horoscopeNode in horoscopeInfo.Descendants(DomainConstants.ZODIACO)
select new HoroscopeInfo
{
Signo = (string)horoscopeNode.Attribute(DomainConstants.SIGNO),
Descripcion = horoscopeNode.Element(DomainConstants.PREDICCION).Value
});
}

Consiguiendo una interfaz rica gracias a AJAX.

Supongo que a estas alturas de la película todo el mundo sabe lo que es AJAX, pues bien aquí vamos a usarlo para conseguir una interfaz medianamente rica.

Lo que vamos a hacer es crear un UserControl, que de forma asíncrona, llame a un WebService y este nos devuelva la información a mostrar.

El WebService

Vamos a empezar por el WebService. Este va a ser muy sencillo y prácticamente lo único que hace es llamar al BC que contiene el código que hemos visto anteriormente. El WebService tiene este aspecto:

[WebMethod]
public List GetHoroscope()
{
HoroscopeBC horoscopeBC = new HoroscopeBC();
List result = null;
try
{
result = horoscopeBC.GetHoroscope();
}
catch
{
// TODO. CPM. Aqui tenemos que logar la excepción
}
return result;
}

Como veis y comentabamos antes, aquí lo único que hacemos es llamar al BC y nuestro WebService no tiene más, aunque solo una cosa, no olvides indicar que este WebService va a ser usado via Ajax, ya que si no no podremos llamarlo. Esto lo añadiendo la propiedad ScriptService. Y quedaría así:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class HoroscopeWS : System.Web.Services.WebService { }

El UserControl

El UserControl, prácticamente lo único que necesita, es el HTML que va a mostrar y una llamada a nuestro JavaScript para que inicie el proceso. El JavaScript lo dejamos para luego y veamos que HTML necesitamos:

<div id="divHoroscope">
<h1>
Horóscopo
</h1>
<img id="imgLoading" src="/Images/loader.gif" alt="cargando" />
<div id="divHoroscopes" style="display:none;">
<select id="ddlHoroscopes" onchange="DdlHoroscopes_Change('ddlHoroscopes', 'divHoroscopes')" ></select>
</div>
</div>

Sencillo verdad, pues si, pero nos falta algo amigos mios, y que nos falta, pues simplemente registrar un proxy del control asp:ScriptManager que tendremos en la página. En este proxy, le vamos a indicar que Scripts necesitamos y que WebService necesitamos. Así que este html nos quedaría asi:

<div id="divHoroscope">
<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server" >
<Scripts>
<asp:ScriptReference Path="~/Scripts/Horoscope.js" />
</Scripts>
<Services>
<asp:ServiceReference Path="~/Services/HoroscopeWS.asmx" />
</Services>
</asp:ScriptManagerProxy>
<h1>
Horóscopo
</h1>
<img id="imgLoading" src="/Images/loader.gif" alt="cargando" />
<div id="divHoroscopes" style="display:none;">
<select id="ddlHoroscopes" onchange="DdlHoroscopes_Change('ddlHoroscopes', 'divHoroscopes')" ></select>
</div>
</div>

El JavaScript

El JavaScript aparte de llamar al WebService y parsear la información de lado cliente, nos va a realizar también operaciones de Interfaz de usuario. Solo voy a hablar de la llamada al WebService y de la función que utilizar para parsearlo, así que vamos allá.

Para llamar al WebService simplemente necesitamos instanciarnos un “objeto” del tipo del WebService y llamar al método. Sería así:

var service = new Horoscope.Web.Services.HoroscopeWS();
var obj = service.GetHoroscope(onComplete);

Esto podemos hacerlo así gracias al ScriptManager que hemos metido en la página y es el framework, el que se ocupa de hacer por debajo las operaciones pertienentes para hacer la llamada real (al final esto usa el objeto de JavaScript XmlHttpRequest). El susodicho ScriptManager tb nos va a proveer de lo necesario para poder operar directamente con objetos complejos vía JSON, lo cual nos facilita mucho la vida.

Tambien podemos observar que cuando llamo a GetHoroscope, le estoy pasando un puntero a la función que ejecuta la respuesta. Este onComplete, lo he implementado así:

function onComplete(args)
{
var objSelectList = document.getElementById(_selectName);
var objContainer = document.getElementById(_divContainerName);
var horoscopesDescription = "";
objSelectList.options.length = 0;
if(objSelectList != null)
{
for (var i in args)
{
var signo = args[i].Signo;
var description = args[i].Descripcion;
objSelectList.options.add(new Option(signo, signo), i);
horoscopesDescription += AddItemToContainer(objContainer, signo, description);
}
objContainer.innerHTML += horoscopesDescription;
SwitchVisibilityControl(document.getElementById(_imageLoaingName), 'none');
SwitchVisibilityControl(objContainer, '');
}
DdlHoroscopes_Change(_selectName, _divContainerName);
}

Esta función recibe un array de parametros. Este array de parametros realmente lo que contiene es la colección de HoroscopeInfo. Todo esto para nosotros es transparente ya que como he dicho antes, es el framework el que se ocupa de ello.

Aquí, unicamente recibimos la respuesta, la parseamos, añadimos a la página la información pertienente y por ultimo ocultamos la imagen.

Para añadir la info a la página estamos usando otra función donde añadimos un bloque de html con los valores correctos. Para hacer el replace estamos usando expresiones regulares (que hay que ser elegantes ;-)), y tiene este aspecto:

function AddItemToContainer(objContainer, signo, description)
{
var returnValue;
var template = "<div id='div#HOROSCOPE_ID#' style='display:none'><h2><a href='#TARGET_LINK#'>#HOROSCOPE_TITLE#</a></h2><p><a href='#TARGET_LINK#'>#HOROSCOPE_DESCRIPTION#</a></p></div>";
returnValue = template;
returnValue = returnValue.replace(/#HOROSCOPE_ID#/gi, signo);
returnValue = returnValue.replace(/#HOROSCOPE_TITLE#/gi, signo);
returnValue = returnValue.replace(/#TARGET_LINK#/gi, _targetLink);
returnValue = returnValue.replace(/#HOROSCOPE_DESCRIPTION#/gi, description);
return returnValue;
}

Asi que para finalizar, ya solo tenemos que llamar desde el html a la función que llama al JavaScript. Asi que nos vamos al UserControl y lo único que tenemos que añadir sería:

<script language="javascript" type="text/javascript">
GetHoroscopes('ddlHoroscopes', 'imgLoading', 'divHoroscopes', '<%=TargetLink %>');
</script>

Y eso es todo amigos, os recomiendo que os bajeis el código de ejemplo y asi podreis ir viendo como va todo, podeis debugar y sintetizar. Y como siempre si teneis alguna duda, pues no teneis nada más que comentarlo y os intentare hechar una mano.

Como resultado veamos una captura del controlito funcionando:

Enlaces relacionados

3 pensamientos en “Ejemplo practico: Mostrando el horóscopo desde una fuente externa con HttpWebRequest, HttpWebResponse, Linq y Ajax

  1. Operadores de Linq: Como usar los operadores Take, StartsWith, EndsWith y Contains « a deshoras

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s