viernes, 28 de diciembre de 2007

Introducción a Ajax

1 - Articulo
2 - Ejemplo

ARTICULO

De Ajax podemos decir muchas cosas y encontrar muchos ejemplos en la Web que nos actualizan combos o que nos permiten realizar alguna acción sin necesidad de llevar a cabo un refresco de página. Así también podemos encontrar una infinidad de controles de asp.net Ajax que se encuentran libres en la Web, los cuales se pueden descarga y, pueden ser utilizados por los desarrolladores, que en mi opinión, son muy buenos cuando debes utilizarlos para cosas puntuales, pero cuando el cliente se vuelve exquisito, no podemos modificarlos. Por ello, en mi caso, prefiero desarrollarlos. Con esto, obtengo un control que puedo modificar a mi gusto.

Claro está que para realizar estas acciones de desarrollo de controles propios, se debe tener mucho conocimiento de javascript, como vengo mencionando desde el inicio del artículo.

Debo destacar que .Net ha mejorado sustancialmente el desarrollo de aplicaciones Web, esto ha generado que muchos de los desarrolladores de hoy en día, dejen de lado la administración de objetos de html en el cliente con javascript, como es el caso de manejo de estilos, creaciones de capas y refrescos de las mismas. El enriquecimiento de las páginas Web siempre está asociado a un buen desarrollo tanto en el cliente como en el servidor.

Ajax, AjaxPro y la tecnología con la que empiezo este artículo, nos permiten realizar un enriquecimiento en cuanto a tiempos de respuesta en un navegador Web, dando la sensación al usuario de que está trabajando en una aplicación de escritorio.

Cuando desarrollo aplicaciones Web con estas tecnologías, siempre me encuentro con un cliente que me pregunta ¡y el historial! y, a veces me dan ganas de responder, en una aplicación para Windows usted tiene un historial. Bueno, sobre este tema, los amigos de Microsoft me han facilitado una URL que comparto con ustedes en donde se describe un control de asp.net Ajax (No AjaxPro), que apalea este problema.

http://www.asp.net/learn/ajax-videos/video-149.aspx

El control History lo pueden encontrar en ASP.NET Futures

Ustedes se preguntarán por que partí este artículo con XMLHttpRequest y no con Ajax, la respuesta es muy simple, ya que Ajax engloba dentro de su Framework XMLHttpRequest, si bien su nombre lo indica (Asynchronous JavaScript And XML) la parte Asincrónica engloba XMLHttpRequest.

Los navegadores que conozco que permiten el uso de Ajax son:

Navegadores basados en Gecko (Mozilla, Mozilla Firefox, SeaMonkey, Camino, K-Meleon, Flock, Epiphany, Galeon y Netscape versión 7.1 y superiores)
Microsoft Internet Explorer para Windows versión 5.0 y superiores, y los navegadores basados en él.
Navegadores con el API KHTML versión 3.2 y superiores implementado, incluyendo Konqueror versión 3.2 y superiores, Apple Safari versión 1.2 y superiores, y el Web Browser for S60 de Nokia tercera generación y posteriores
Opera versión 8.0 y superiores, incluyendo Opera Mobile Browser versión 8.0 y superiores.
Si bien es cierto, que para las personas que trabajamos con Remote Scripting, Ajax, presenta un comportamiento de transferencia de datos desde una solicitud de cliente a un servidor y vise versa muy similar, pero con Ajax, se han mejorado la forma de transferir la información y, las entregas de esta, ya que se realizan a través de XML, en donde el resultado es un Html que es desplegado en la zona requerida o un resultado de filas con columnas, como generalmente se observa en los tutoriales de Ajax.

Ventajas.

Buena, las ventajas de trabajar con Ajax son similares a las que describo para al trabajar con método asíncrono, aunque la transmisión de información está limitada, así como el tiempo de espera, aunque en la llamada al Namespace de Ajax desde javascript permita aumentar el tiempo.

Desventajas.

El manejo del Historial, ya que no queda registrado en todos los navegadores descritos, aunque los amigos de asp.net Ajax se la han currado y han creado un objeto que apalea el problema, no puedo asegurar de que funcione en todos los navegadores.

Solución

Utilizar el control descrito para los navegadores que lo soporten y tratar de modificar el hash en los otros navegadores, aunque creo que los amigos de asp.net Ajax tienen bastante controlado el problema.


EJEMPLO

En el ejemplo que plantearemos trataremos de realizar la misma acción que definimos anteriormente, con la diferencia de que ahora estaremos trabajando con otro tipo de funciones definidas en javascript, y todo se realizará en la misma página, para ello ahora trabajaremos con una sola página y, en este caso retornaremos el texto sin escribir una página Web, aunque mi consejo, para este tipo de tecnología, es utilizar Ajax con Xslt y Xml, con lo cual se obtendrá muy buenos resultados.

Como prerrequisito necesitamos descargarnos la dll de Ajax, luego debemos incluirlas en nuestro proyecto y agregar una referencia a esta.
Como siguiente paso antes de realizar el ejercicio debemos tener configurados los parámetros de uso en el web.config, en donde en el nodo agregaremos las siguientes líneas de código:

<httpHandlers>
<add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax" />
&lt/httpHandlers>

Ahora si podemos empezar a configurar nuestra aplicación para realizar las solicitudes que desplegarán la información deseada. Para ello, en el archivo .aspx.vb que hemos creado, debemos agregar dentro del método que atiende el eventos load, las siguientes líneas de código Ajax.Utility.RegisterTypeForAjax(GetType(_Default))

Donde _Default, corresponde al nombre de la clase que está asociada a la página Web

Quedando de la siguiente forma:

Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Ajax.Utility.RegisterTypeForAjax(GetType(_Default))

End SubEnd Class

Si desean, pueden cambiar el nombre de la clase, para identificar las llamadas que se hagan desde javascript, pero deben recordar actualizar el nombre en la sociación de la directiva Page en la página .aspx, que se encuentra en la primera linea del html.

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

Yo cambiaré el nombre de la clase a AjaxEjemplo.

A continuación crearé el método que retornará la información según el parámetro entregado, este método puede tener diversos tipos String, XMLDocument, estructura de clases, etc.

Se debe considerar que si se devuelve una estructura de clase el innerHTML que captura la función de resultado tendrá un value y luego el dato, es decir innerHTML.value.dato, en donde el dato es uno de los parámetros de la clase. Adicionalmente se debe considerar que la clase debe ser definida como Serializada.

En este caso definiremos las funciones como String, ya que estamos retornando un resultado HTML, en el caso de que estemos trabajando con XSLT y XML.
Adicionalmente, agregaremos en el método una opción que retorne un error, para que se observe el efecto de error que también puede ser manejado en el cliente, quedando la función de la siguiente forma:

<Ajax.AjaxMethod()> _
Public Function funOpcionRescatar(ByVal opc As String) As String
Dim strReturn As String = ""
Try
If opc.Trim <> "" Then
Select Case opc
Case "1" : strReturn = "Ha seleccionado la opcion 1"
Case "2" : strReturn = "Ha seleccionado la opcion 2"
Case "3" : Throw New Exception("No existe la opcion 3")
End Select
End If
Catch ex As Exception
Throw ex
End Try
Return strReturn
End Function

Ahora definiremos las dos funciones en javascript que permitirán realizar la solicitud de datos y la captura de información, para ello crearemos un script con las siguientes líneas de código:

function funLlamadaAjax(opc){
AjaxEjemplo.funOpcionRescatar(opc, funLlamadaAjax_CallBack);
}

function funLlamadaAjax_CallBack(res){
if (res.error){
alert(res.error);
}else{
document.getElementById("divContenido").innerHTML = res.value;
}
}

Nótese, que en la primera función realizamos una llamada al método de Ajax que se ha creado en el servidor y, que le pasamos el nombre de la función que capturará los resultados.

La función que captura los resultados verifica que no existan errores, en el caso de que exista salta una excepción en el cliente, sino, se realiza el despliegue del resultado.

Es aquí en donde podríamos, a través de javascript actualizar la información de las zonas o capas que estamos utilizando, ya que si estoy retornando un esquema de clase serializada, existirán tantos datos como los que se hayan definido en el cuerpo de la clase. Así mismo podríamos retornar un array de datos, como por ejemplo un resultado de datatable o en el mejor de los casos retornar un resultado de una página que ya se ha ejecutado en el servidor como es el caso de trabajar con XSLT y XML.

Lo que nos queda es definir el cuerpo del HTML el cual quedará de la siguiente forma:

<body>
<div>
<a href="javascript:funLlamadaAjax(1);">Primera opción</a>
<a href="javascript:funLlamadaAjax(2);">Primera opción</a>
<a href="javascript:funLlamadaAjax(3);">Tercera opción</a>
</div>
<div id="divContenido">

</div>
</body>

Ejecuten la aplicación y podrán observar el comportamiento funcional de las solicitudes en Ajax.

Espero que este pequeño artículo les sirva de ayuda en la toma de decisiones para definir que utilizar.

No se si sea pronto o no, pero en el próximo artículo que escriba hablaremos de AJAXPro, que en su versión para Visual Studio es muy interesante. Sobretodo para las personas a las que nos gusta trabajar con controles personalizados, no digo que sea mejor o peor que lo antes planteado, solo digo que es una opción más que amplía nuestras perspectiva al momento de desarrollar aplicaciones.


JavaScript con Ajax

1 - Articulo
2 - Ejemplo
3 - Resumen


ARTICULO

En este artículo veremos como se puede trabajar con Ajax y JavaScript, pero antes de continuar quisiera recalcar que es muy importante que los programadores Web, no dejen de lado el aprendizaje de JavaScript, ya que esta forma de desarrollar es la clave del éxito de Ajax, AjaxPro, HttpRequest, XSLT o cualquier tipo de transmisión de datos entre cliente y servidor. Se torna muy importante que los programadores manejen muy bien la creación de objetos y estilos con JavaScript, ya que es primordial, como ejemplo, poder saber, que en vez de hacer pantallas emergentes, puedes escribir capas sobre las páginas desplegadas que bloqueen lo que queda atrás, hasta que el usuario realice la acción deseada. Esto lo podremos ver más adelante, pero debo detallar que en reiteradas ocasiones me ha tocado ver a programadores que no se manejan muy bien en JavaScript y permítanme decirles que esto es clave para el éxito de una buena programación Web (Esto me lo dijeron a mí un día y ahora se los comparto a ustedes).

Ahora sin más, ya que todo esta dicho, vamos al ejemplo y repetiremos algunos pasos del de introducción a ajax para que quede claro como configurar la dll


EJEMPLO


En el siguiente ejemplo, veremos como desplegar un combo box utilizando javascript en la carga de la página. A medida que avanza el ejemplo, veremos como ir mejorando el ejercicio para ver un despliegue de datos de usuario, según su apellido seleccionado y compararemos cuanto código en JAVASCRIPT se va al cliente.

Como ya sabemos, debemos crea una solución y a esta asociar una referencia a la librería de AJAX que utilizaremos, en este caso Ajax.dll (Recomiendo crear el directorio bin en el proyecto y copiar la dll en este).

Como siguiente paso, agregaremos en el WEB.CONFIG, dentro del nodo system.web, las siguientes líneas, las cuales nos permitirán realizar la referencia a la dll de AJAX que hemos referenciado.

<httpHandlers>
<add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax"/>
</httpHandlers>

Ahora, lo primero que haremos será definir un archivo .aspx que llamaremos inicio.aspx y realizaremos la definición del tipo que será utilizado por ajax en el método que atiende el evento load de la página, antes de esto renombraremos el espacio de nombre de la clase de _Default a Inicio. Esto nos permitirá trabajar con el mismo nombre en el caso de que renombren la página Default.aspx que se crea por defecto.

Como el artículo anterior lo escribimos en Visual Basic, el actual lo escribiremos en C#. La clase y el método quedan de la siguiente forma:

public partial class Inicio : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e) {
Ajax.Utility.RegisterTypeForAjax(typeof(Inicio));
}
}

Como mencionamos anteriormente, veremos como deberíamos cargar la información si es que utilizamos javascript. Para ello crearemos un método en el servidor que retornará los registros a javascript y este se encargará de desplegarlos en el html. Como base de datos, utilizaremos la bien ponderada y conocida por todos, Northwind.

NOTA: No haremos el ejercicio a tres capas ya que nos quitaría mucho tiempo, por lo cual utilizaremos los controles de Bases de Datos SqlConnection, SqlDataAdapter y un DataSet. Con esta intensión, es que, tendremos que importar los espacios de nombre:

using System.Data;
using System.Data.SqlClient;

El siguiente paso será crear el método que nos retornará la información de los empleados desde la tabla Employes, de la siguiente forma:

[Ajax.AjaxMethod()]
public DataSet getEmpleado() {
DataSet ds;
try{

String strCnx = "Data Source=(local);" +
"Initial Catalog=Northwind;" +
"Integrated Security=True";

String strSql = "select EmployeeID, LastName " +
"from Employees";

SqlConnection cnx = new SqlConnection(strCnx);
SqlDataAdapter da = new SqlDataAdapter(strSql, cnx);
ds = new DataSet();

da.Fill(ds);
}
catch (System.Exception ex){
throw ex;
}
return ds;
}

Como se puede observar , estamos devolviendo un objeto, que en ocaciones, si este objeto contiene mucha información, el tiempo de respuesta de entrega y de tratado de esta en el cliente puede ser muy largo, por lo cual yo recomiendo cargar la información en el servidor y entregar, en vez de un objeto un string con el html listo.

Antes de ver como trabajar con xslt tendremos que ver como podemos desplegar desde javascript la información, para ello, en el código HTML realizaremos las siguientes acciones:

Dentro del Div que se ha creado en el código HTML agregaremos las siguientes líneas de código, quedando todo el body del html de la siguiente forma:

<form id="frm" runat="server">
<div>
<select id="sltEmpleado" >
</select>
</div>
</form>

El siguiente paso será crear en el espacio de nombre del nodo de script del código HTML la función que realizará la llamada al método que nos retornará la información, para ello realizaremos las siguientes acciones:

<script language="javascript">
function getEmpleado(){
Inicio.getEmpleado(getEmpleado_callback);
}

function getEmpleado_callback(res) {
if (res.error!=null){
alert(res.error);
}else{
for( i=0; i<res.value.Tables[0].Rows.length; i++) {
var opcion = document.createElement("OPTION");
document.frm.sltEmpleado.options.add(opcion);

opcion.id = res.value.Tables[0].Rows[i].EmployeeID;
opcion.innerText = res.value.Tables[0].Rows[i].LastName;
}
}
}
</script>


Analisemos un poco el código creado.

En la función getEmpleado, realizamos una llamada al método del servidor este responde y, el resultado se despliega en la función getEmpleado_callback, en la cual se toma el objeto retornado y actualiza la información. Si bien es una buena forma de desplegar la información, que pasaría si en el objeto viniera más de una tabla o más de 10 registros, el despliegue sería tan eficiente. Esta técnica solo la recomiento para pequeños volumenes de información.

Como segunda observación, podemos concluír que si no somos cuidadosos en crear sinónimos en las consultas a la base de datos, el cliente podrá saber cuales son los campos de datos con los cuales estoy trabajando y esto en vez de ocultar la información al usuario final, esta permitiendo que el usuario conozca los campos con los cuales trabajo. Algunos dirá, puedo ponerlos en un archivo .js, pero que pasa si el que está revisando es avispado y descarga los links que definimos para llamar a nuestros archivos. Esta solución debe ser estudiada con mucho detalle antes de ser utilizada.
Bueno, solo nos queda realizar la llamada, para ello en el nodo body agregaremos una llamada a la función getEmpleado, utilizando la instrucción onload, quedando todo el HTML de la siguiente forma:

<body onload="javascript:getEmpleado();">
<form id="frm" runat="server">
<div>
<select id="sltEmpleado" >
</select>
</div>
</form>
</body>



RESUMEN

Una de las desventajas de la respuesta de Ajax en JavaScript, es el tratamiento de los errores, ya que para desplegar estos tenemos que utilizar la sentencia res.error, que despliega el tipo de error con el mensaje. En cambio AJAXPRO permite desplegar el problema en cuestión, es decir, utilizamos la sentencia res.error.Message, que rescata el error en cuestión para ser desplegado, permitiendonos definir nuestros propios mensajes de errores.

XMLHttpRequest

1 - Articulo
2 - Ejemplo
3 - Resumen


ARTICULO

XMLHttpRequest- ActiveXObject

XMLHttpRequest-ActiveXObject es una tecnología de traspaso de datos muy poco comentada pero muy potente y, no requiere ningún tipo de objeto que debe instalarse en las aplicaciones para funcionar, como es el caso de Ajax y AjaxPro. Existe una estrecha relación entre este tipo de transmisión de información y javascript (XMLHttpRequest y ActiveXObject pertenece a la biblioteca de javascript window, es decir, window.XMLHttpRequest – window.ActiveXObject.

Cuando se realiza uno de estos tipos de solicitud, se invoca una llamada a una URL específica que es retornada y escrita en una zona definida, generalmente en un DIV de HTML u otro tipo de capa, utilizando el método de javascript “innerHTML” (Este método lo veremos en todos los tipos de objetos que comentaremos).

- Si estamos trabajando con navegadores como IE y dependiendo de la versión del navegador que estemos utlizando, crearemos un objeto con ActiveXObject.

- En el caso de que estemos trabajando con otro tipo de navegador, como Mozilla, Safari, etc., crearemos un objeto con XMLHTTRequest

Este tipo de transacciones permite realizar una llamada asincronica a cualquier tipo de URL, pudiende ser, una imagen, una página estática (html) o páginas dinámicas que se ejecutan en un servidor y que retornan un resultado específico.
El resultado de la llamada al servidor será capturada por el cliente y desplegada en la zona definida para ello.

Ventajas Observadas

Podemos utilizar este tipo de metodología para realizar llamadas a páginas dinámicas que entregarán un resultado en respuesta a parámetros entregados, claro esta que también responde muy bien para desplegar imágenes o páginas estáticas. Destaco la primera opción ya que como persona que participa en proyectos me interesaría definir una lógica de transformación de datos en el servidor y enviar como resultado el HTML creado para ser desplegado en el cliente, o desplegar páginas que tendrán un comportamiento funcional en una zona específica.

Desventajas Observadas.

Con esta metodología, no queda registrado en el history del navegador, las llamadas que se han realizado, por lo cual solo se observará un history en la página principal que se despliega al inicio de la llamada. Este problema se observará en las otras metodologías, aunque en Ajax existe un control que se ha desarrollado para apalear el problema.

Solución de desventajas.

En navegadores como Mozilla, es posible escribir el history interviniendo el método hash de window.location, utilizando javascript, esto funciona muy bien para navegadores como Mozilla, pero para navegadores con IE, según lo que he averiguado, debe implementarse en un iframe la página. Este problema lo tendremos también con Ajax y AjaxPro, aunque como mencioné en Ajax existe un objeto que propone apalear el problema.

Bueno, no puedo cerrar esta fase sin hacerles un ejemplo simple de este tema. En las siguientes líneas se mostrará un ejemplo de este tipo de llamadas para desplegar, según un dato entregado una imagen en específico. Como es un ejemplo simple no mostraré como realizar acciones sobre Bases de Datos, pero al ver la página aspx podrán, intuitivamente, darse cuenta de que es aquí en donde deben experimentar.

volver

EJEMPLO

Antes que todo, hablaremos sobre el ejemplo, en el cual se observa que utilizando una URL, con esto desplegaremos una página en una capa, en este caso un DIV de HTML que se actualizará con javascript, para ello primero deberemos definir las funciones de java que identificarán que objeto debe crearse y luego la lógica de llamada y de despliegue del resultado. Luego construiremos una página HTML que realizará la llamada a nuestra página Web, por ultimo construiremos una página Web en aspx que retornará, según un parámetro entregado en la llamada, un texto de respuesta que será cargado en un label desde el método que atiende el evento load de la página. Yo pongo el ejemplo, ustedes los textos y si lo prefieren las imágenes.

1. Crear las funciones en javascript, por mi parte crearé un archivo a parte que llamaré asincronica.js que debe contener el siguiente código:

Función de creación de objeto.

function funObjetoCrear(oPagina){
// verificamos que tipo de navegador se está utilizando
if (window.XMLHttpRequest) {
// en el caso de que sea Mozilla u otro distino a IE
oPagina = new XMLHttpRequest()
} else {
/*
antes de crear el objeto en IE, en el caso de que
no se cumpla la primera opción, se debe verificar
que los controles activex existen, en caso contrario
no podremos crear el objeto que lleva a transacción
*/
if (!window.ActiveXObject){
return false;
}else{
/*
para las ultimas versiones de IE se crea un
objeto ActiveXObject("Msxml2.XMLHTTP")
*/
try { oPagina = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e){
/*
si es una versión anterior de IE se crea un
objeto ActiveXObject("Microsoft.XMLHTTP")
*/
try{ oPagina = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e){}
}
}
}
return oPagina;
}

Función de despliegue de resultado.

/*
dependiendo de ciertas condiciones que deben cumplirse se realizar el despliegue de información en la capa definida para ello utilizando el método innerHTML, que dijimos que utlizaríamos en estas demostraciones
*/
function funDivCargar(oPagina, strContenedor){
if (oPagina.readyState == 4 &&
(oPagina.status==200 window.location.href.indexOf("http")==-1)){
document.getElementById(strContenedor).innerHTML = oPagina.responseText
}
}

Función que llama a la creación del objeto y al despliegue.

function funLlamadaEjecutar(strUrl, strContenedor){
var oPagina = false;

oPagina = funObjetoCrear(oPagina);

oPagina.onreadystatechange =
function(){ funDivCargar(oPagina, strContenedor); }

oPagina.open('GET', strUrl, true);
oPagina.send(null);
}

2. Creación de la página que realizará la llamada y del despliegue.

Antes de definir en el body de la página, el html que utilizaremos, tendremos que agregar dentro del cuerpo del head o donde ustedes quieran, la llamada al archivo .js creado.
Una vez realizada esta acción se presenta el código html que utilizaremos.

<body>
<div id="mnuLink">
<a href="javascript:funLlamadaEjecutar('Default.aspx?id=1', 'divContenido');"> Primera opción</a>
<a href="javascript:funLlamadaEjecutar('Default.aspx?id=2', 'divContenido');"> Segunda opción</a>
</div>

<div id="divContenido">
</div>

Si se observa, es en el segundo DIV donde se debe desplegar la página que llamaremos.

3. Por ultimo crearemos la página que retornará los textos o las imágenes (según definieran), esta página se llamará, para mi ejemplo la muy conocida y bien ponderada default.aspx, en donde agregaremos un control label de aspx, Para luego escribir las siguientes líneas en el método que atiende el evento load de la aplicación:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
If Not Request("id") Is Nothing Then
Dim opc As String = Request("id").ToString()

Select Case opc
Case "1"
Me.Label1.Text = "Despliegue de la primera opción"
Case "2"
Me.Label1.Text = "Despliegue de la secunda opción"
End Select

End If

Catch ex As Exception
Response.Write(ex.Message)
End Try

End Sub

Ahora si ejecutamos la aplicación veremos que los cambios se realizan sin problemas.

volver

RESUMEN

Este tipo de operación, no requiere ninguna dll adicional o configuración en el archivo web.config para operar, solo se necesita que el navegador tenga definido y habilitados los objetos que se necesitan para operar.

Como consejo, este tipo de operaciones se puede realizar con llamadas a páginas que necesitan desplegar un resultado, estos despliegues se pueden hacer con archivos aspx, como en el ejemplo, archivos xslt, archivos estáticos o cualquier otra página, estática o dinámica que se desee desplegar.

volver