Showing posts with label Ajax. Show all posts
Showing posts with label Ajax. Show all posts

Monday, July 07, 2008

[AJAX] Emular el UpdateProgress con ModalPopup


por Ing. Juan Pablo Ibañez
http://ing.juanpablo.googlepages.com

Uno de los controles mas usados de la librería AJAX de Microsoft (ajax.asp.net) es el control UpdatePanel. Este control nos permite hacer un postback parcial de la página y solamente modificar una sección de la misma sin tener que recargar completamente la página. Cuando este postback parcial demora mucho, es conveniente mostrarle el estado al usuario, generalmente se muestra un mensaje como por ejemplo "cargando...", "loading...", "procesando...", etc.
La librería AJAX de Microsoft nos permite hacer esto mediante el control UpdateProgress. Usar este control es sumamente fácil, lo que debemos hacer es definir en un div, por ejemplo, el templete que deseamos que se muestre cuando se está realizando un postback asíncrono.

Un ejemplo de UpdateProgress seria:

<asp:UpdateProgress ID="UpdateProgress1" runat="server">

    <ProgressTemplate>

        An update is in progress...

    </ProgressTemplate>

</asp:UpdateProgress>


Cuando algunos de los UpdatePanel que tenga nuestra página .aspx haga un postback parcial, aparecerá el UpdateProgress y el usuario sabrá que debe esperar hasta que se actualice la parte de la página que está englobada en el UpdatePanel.

Hasta aquí es todo muy simple, el problema surge generalmente cuando el usuario no espera que se actualice la página y hace click nuevamente en el botón, o en otros botones y genera sucesivos postback parciales de la página. Para evitar esto existen varias soluciones:
  1. Deshabilitar del lado del cliente por Javascript todos los controles que hagan postback al servidor hasta que finalice la actualización parcial de la página. El problema es que requiere mucho código Javascript para hacerlo. Si agregamos un control nuevo, tenemos que modificar nuestra rutina para contemplar este nuevo control.
  2. Otra opción, que es la razón de este artículo es utilizar un ModalPopup que cuando presionemos cualquier control que haga un postaback parcial aparezca bloqueando toda posibilidad de que el usuario haga un click en otro control. La ventaja de esta solución es que podemos implementarla de manera tal que sea independiente de la cantidad de controles que tenga nuestra página y de cantidad de páginas que tenga nuestro sitio, etc, etc, etc.

Los elementos que debemos utilizar en esta segunda opción son:
  1. MasterPage.
  2. ModalPopup.
  3. Sys.WebForms.PageRequestManager.

La idea es armar un esquema que no necesite ser replicada en cada una de los webforms que creemos en nuestra aplicación, es por eso que utilizaremos una MasterPage. Es decir en nuestra MasterPage tendremos definido el ModalPopup y el Javascript necesario para hacerlo aparecer, cuando se lance una petición de postback parcial por cualquiera de los controles definidos en cualquiera de nuestros webforms que tengan seteada nuestra MasterPage y también ocultar el ModalPopup cuando la actualización esté terminada.

Muestra MasterPage podría ser:

<%@ Master Language="C#" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

    <head runat="server">

        <title></title>

    </head>

    <body>

        <%-- Código Javascript --%>

        <form id="form1" runat="server">

            <div>

                <asp:ScriptManager ID="ScriptManager1" runat="server"

                    EnableScriptGlobalization="True"

                    EnableScriptLocalization="True">

                </asp:ScriptManager>

                ESTA ES UNA MASTER PAGE

                <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">

                </asp:contentplaceholder>

            </div>

            <%-- ModalPopup --%>

        </form>

    </body>

</html>


Una vez que tenemos nuestra MasterPage lo que debemos definir en esta es el ModalPopup. Un ejemplo de ModalPopup sería:


<asp:LinkButton ID="LinkButton1" runat="server" Visible="true"/>

<asp:Panel ID="Panel" runat="server" Style="display: none">

    <table class="modalPopUp" border="0" cellpadding="0" cellspacing="0">

        <tr class="modalPopUpTopRow">

            <td valign="middle">

                <img src="images/ajax-loader.gif" alt="procesando..." />

            </td>

        </tr>

        <tr>

            <td align="center">

                Procesando...

            </td>

        </tr>

    </table>
</asp:Panel>

<cc1:ModalPopupExtender ID="ModalPopupExtender" runat="server"

    BehaviorID="programmaticModalPopupBehavior"

    TargetControlID="LinkButton1"

    PopupControlID="Panel"

    BackgroundCssClass="modalBackground"/>

Basicamente es ModalPopup tiene un gif animado y una leyenda de "Procesando...". O sea que cuando algún control haga una petición de postback parcial aparecerá este ModalPopup indicando que debe esperar a que termine la actualización de la página evitando que el usuario pueda hacer click en cualquiera de los controles.


Lo que falta ahora es el código Javascript que hacer aparecer y desaparecer el ModalPopup cada vez que comienza y finaliza un request.

Para esto haremos uso del objeto PageRequestManager y le añadiremos 2 funciones una para el evento beginRequest y otro para el evento endRequest.

Estas funciones lo que hacen es buscar el BehaviorID del ModalPopup y una vez que obtenemos la referencia al ModalPopup llamar al método hide() o show() del ModalPopUp.


<script type="text/javascript">

    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(

        function (sender, arg){

            var modalPopupBehavior = $find('programmaticModalPopupBehavior');

            modalPopupBehavior.hide();

        }

    );

   

    Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(

        function (sender, args) {

            var modalPopupBehavior = $find('programmaticModalPopupBehavior');

            modalPopupBehavior.show();

        }

    );

</script>

Friday, May 09, 2008

[AJAX] Carga dinámica de páginas ASPX con AJAX Enabled WebService

por Ing. Juan Pablo Ibañez
http://ing.juanpablo.googlepages.com

Con la aparición de AJAX, ahora podemos cargar ciertas partes de una página ASPX sin tener que recargar toda la página. El problema surge cuando en una página queremos incluir diferentes funcionalidades que habitualmente están en páginas separadas. Si intentamos incluir todas las funcionalidades en nuestra página e ir cargándolas mediante AJAX, nuestra página comienza a hacerse demasiado grande para poder albergar todo el código que permite cambiar las partes y mostrar las distintas funcionalidades sin recargar toda la página. Hay aplicaciones grandes que requieren utilizar otro enfoque, como ser cargar páginas ASPX dentro de páginas ASPX pero sin hacer PostBack de la página contenedora. La técnica explicada en este artículo nos permite tener nuestra aplicación dividida en todas las páginas ASPX que necesitemos, y cargarlas dentro de una página contenedora usando AJAX, lo cual nos permite dividir mejor la funcionalidad, distintos equipos pueden trabajar independientemente en cada página ASPX, nuestra aplicaciones está mas desacoplada, prolija y demás beneficios.

En el siguiente ejemplo voy a mostrar como cargar diferentes ASPX dentro de otra página ASPX haciendo uso de AJAX WebServices. La imagen [Imagen1] que vemos a continuación es un esquema de lo que se pretende hacer.


[Imagen1]

La página contenedora tiene 1 div donde se insertará mediante AJAX el HTML de las páginas ASPX que se quieran cargar dinámicamente dentro de la página contenedora. Si nuestras ASPX que queremos cargar tiene elementos que hacen PostBack, debemos cargarlas dentro de un iframe, de lo contrario, por ejemplo, al presionar un Button en la página que se cargo dentro de la contenedora, se hará un PostBack que recargará también nuestra contenedora y la idea es que la contenedora nunca se recargue completamente.

Nuestra solución entonces deberá tener al menos los componentes que se muestran en la siguiente imagen [Imagen2].

Como vemos en esta imagen del Explorador de Soluciones, tenemos:
          1. Default.aspx, nuestra página contenedora.
          2. Default.js, código Javascript para hacer la llamada al WebService y cargar el contenido que este devuelve en nuestro div.
          3. Page1.aspx, una de las páginas que queremos cargar dentro de Default.aspx
          4. Page2.aspx, otra de las páginas que queremos cargar dentro de Default.aspx
          5. PageLoader.asmx, el WebService que devuelve el HTML que vamos a cargar dentro del DIV de Default.aspx
          6. web.config, configuración para hacer uso de las librerías de AJAX ASP.NET y configuración para usar AJAX ASP.NET WebServices.
          7. ajax-loader.gif, imágenes que mostramos mientras se cargan las páginas interiores.




[Image2]

La idea es que nuestra página Default.aspx tenga un DIV donde cargar el HTML de las páginas que queremos cargar, haga una llamada a un AJAX Enabled WebService y mientras se carga la página interior muestre un Loading...

La estructura de nuestra página Default.aspx sería algo así:

<body>

    <form id="form1" runat="server">

        <asp:ScriptManager ID="ScriptManager1" runat="server">

            <Scripts>

                <asp:ScriptReference Path="Default.js" />

            </Scripts>

            <Services>

                <asp:ServiceReference Path="PageLoader.asmx" />

            </Services>

        </asp:ScriptManager>

        <div align="center">

            <h2>Página Contenedora</h2>

            <input id="btnLoadPage1" type="button" value="Cargar Página 1" onclick="return btnLoadPage1_onclick()" />

            <input id="btnLoadPage2" type="button" value="Cargar Página 2" onclick="return btnLoadPage2_onclick()" />

            <br />

            <hr />

            <br />

            <div id="Loading" style="display: none">

                <table style="width: 200px; height: 200px">

                    <tr>

                        <td align="center" valign="middle">

                            <img id="Img1" src="Images/ajax-loader.gif" alt="loading..." />

                        </td>

                    </tr>

                </table>

            </div>

            <div id="Target">

            </div>

        </div>

    </form>

</body>


Tenemos un ScripManager configurado para tener acceso a nuestro código JavaScript:

<Scripts>

  <asp:ScriptReference Path="Default.js" />

</Scripts>

y también le configuramos el path a nuestro WebService para que pueda crear automáticamente el proxy que vamos a usar desde nuestro código JavaScript:
<Services>

    <asp:ServiceReference Path="PageLoader.asmx" />

</Services>


También tenemos 2 HTML Buttons, uno para llamar a Page1.aspx y otro para Page2.aspx y además 2 divs, uno para mostrar la imagen de Loading mientras se carga la página interior y otro para cargar el HTML que devuelve el WebService.


Al presionar cualquiera de los botones se hace una llamada al AJAX Enabled WebService como vemos en el siguiente código:


function btnLoadPage1_onclick()
{
    ret = PageLoader.LoadPage("Page1.aspx", OnComplete, OnTimeOut, OnError);
    document.getElementById('Loading').style.display = 'block';
    return(true);
}
function btnLoadPage2_onclick()
{
    ret = PageLoader.LoadPage("Page2.aspx", OnComplete, OnTimeOut, OnError);
    document.getElementById('Loading').style.display = 'block';
    return(true);
}

function OnComplete(args)
{
    document.getElementById('Target').innerHTML = args;
}

function OnTimeOut(args)
{
    alert("Service call timed out.");
}

function OnError(args)
{
    alert("Error calling service method.");
}


PageLoader es el proxy creado por el ScriptManager y LoadPage es el [WebMethod] expuesto por nuestro WebService. La llamada es asíncrona por lo que nos pide que especifiquemos la función que se va a llamar cuando se haya completado la petición, la función que se llama si se produce un time out y la función que se llama si se produce un error.

O sea que las funciones de los botones hacen 2 cosas: la petición y mostrar la imagen de Loading.

Una vez que el AJAX Enabled WebService devuelve el HTML, cargamos este dentro del div "Target" en la función OnComplete.

Lo que queda ahora es ocultar el Loading, esto lo hacemos desde la página interior, por ejemplo, Page1.aspx, en el evento onload en el body:

<body onload="parent.document.getElementById('Loading').style.display='none';" style="margin:0px;">

    <form id="form1" runat="server">

        <table style="width:200px;height:200px;">

            <tr>

                <td valign="middle" align="center" style="background-color:Blue;color:White">

                    Page1.aspx

                </td>

            </tr>

        </table>

    </form>

</body>


Solo quedaría ver el WebService, que lo que hace basicamente es devolver un HTML con un IFRAME con la página que le pasamos como parámetro, de esta forma si nuestra Page1.aspx o Page2.aspx hacen un PostBack, este no afecta a la página contenedora.


[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.Web.Script.Services.ScriptService]

public class PageLoader : WebService

{

    [WebMethod]

    public string LoadPage(string pageName)

    {

        return @"<iframe frameborder='0'

                         scrolling='no'

                         marginheight='0'

                         marginwidth='0'

                         height='200px'

                         width='200px' id='frame' src='" + pageName + "' runat='server'></iframe>";

    }

}


Es importante destacar la siguiente línea que es la que permite que el hacer AJAX Enabled al WebService:


[System.Web.Script.Services.ScriptService]


El siguiente gif animado muestra el ejemplo funcionando:






Thursday, November 29, 2007

[AJAX] Identificando Full PostBack y AJAX AsyncPostBack

Para aquellas personas que hayan usado AJAX ASP.NET un poco mas en profundidad que sólo arrastrar un UpdatePanel este artículo les va a resultar muy útil.
Un UpdatePanel nos permite refrescar ciertas partes de la página, en vez refrescar la página completa usando un Full PostBack.
Ahora depende como hayamos programado nuestra aplicación estaremos usándo AJAX de una manera más performante o no.
Cuando se produce un evento dentro de un UpdatePanel o un trigger que activa un UpdatePanel, se ejecuta el ciclo de vida completo de una página ASP.NET pero no se refresca toda la página sino que el objeto PageRequestManager (client-side) se encarga de recibir el nuevo HTML y reemplazar el viejo HTML.
Ejecutar el ciclo de vida completo de la página significa que se ejecutan todos los eventos del ciclo de vida de la pagina como ser Load,PreInit, Init, etc, etc.

Es en el evento Load donde se puede preguntar si es un Full Postback o un AJAX AsyncPostBack y definir distintas funcionalidades dependiendo de que sea uno u otro. Esto es muy importante tenerlo en cuenta ya que muchos desarrolladores solo preguntan si es un Full PostBack o si es la primera vez que se ejecuta la página y pierden la posibilidad de optimizar sus aplicaciones corriendo las funciones que necesitan para cada caso.
Ahora, con es uso de AJAX, tenemos 3 alternativas: que sea la primera vez que se ejecuta la página, que sea un Full PostBack o que sea un AJAXAsyncPostBack.

Veremos ahora como hacer esto en el código:



Como se ve en el ejemplo se consulta al objeto ScriptManager para saber si es un AsyncPostBack y se consulta al objeto Page para saber si es un Full PostBack.

Wednesday, October 24, 2007

[AJAX]Tecnología AJAX

Luego del boom de los .com, la web entró en una meseta hasta el año 2005 donde renació con lo que hoy es conocido como Web 2.0. Este resurgimiento ha sido fomentado, entre otras cosas, por cambio en el paradigma en la forma en que se publican los datos, la mejora en las telecomunicaciones y las nuevas tecnologías como AJAX que fomentaron a que el nuevo modelo de web sea mas interactivo y le permita al usuario tener una experiencia mas rica y mas interactiva con los contenidos a los cuales está accediendo.

Hoy ya no son los editores de contenidos quienes publican la información y el resto de la comunidad es un mero espectador, sino que es la comunidad misma la que crea, participa y juzga el contenido de los portales. Pero estas nuevas activadas, que ahora realiza la comunidad, deben ir acompañadas por mejoras tecnológicas que permitan, a gente que no es experta en sistemas informáticos, realizarlas de una manera sencilla, simple, dinámica y productiva.

Las tecnologías AJAX están presentes en las interfaces gráficas de GMAIL, MySpace, Knowii, Meebo, entre otras.

AJAX es el acrónimo de Asynchronous Javascript and XML y es una técnica de programación donde se combinan y se explotan tecnologías ya existentes como JavaScript y XML, para lograr enviar y recibir mensajes en segundo plano sin que el usuario note que la pagina web que navegando esta procesando algunas tareas, es decir sin que se realicen postbacks. El uso adecuado de AJAX trae como consecuencia un aumento considerable de la usabilidad, productividad, velocidad y tiempo de respuesta de un sitio web.

AJAX ASP.NET Framework

Uno de los frameworks de AJAX mas usados es AJAX ASP.NET, que será el usado en este artículo a modo de ejemplificación para mostrar algunas de las tareas que podemos realizar con esta tecnología.

Este framework permite implementar AJAX en sitios ASP.NET mediante el uso de controles de servidor. Siguiendo con la forma de trabajo de ASP.NET, los desarrolladores programan sus aplicaciones de la manera convencional y cuando desean usar una funcionalidad AJAX solo debe agregar unos de los controles que las extensiones AJAX ASP.NET proveen y el framework se encarga de realizar la generación del Javascript correspondiente para realizar los procesos en segundo plano.
También existe la posibilidad de usar este framework mas a fondo, optimizando el rendimiento, programando ciertas tareas desde Javascript combinando con Servicios Web para evitar el procesado completo del ciclo de vida de una pagina ASP.NET.

Es un framework muy potente, que si integra perfectamente con Visual Studio y ASP.NET 2.0, y también cuenta con un AjaxControlToolkit, que es un conjunto de controles que permiten llevar la interactividad al máximo.

Utilizando AJAX ASP.NET Framework en un caso real

Utilizando este framework es muy interesante, entre otras cosas, obtener datos de un servicio web asíncronamente y devolver el resultado del mismo sin hacer un postback de la página, optimizando el rendimiento y llevando el uso del framework a su máximo poder.

Supongamos que tenemos un conjunto de web services que resuelven nuestra lógica de negocios, se encargan de interactuar con la base de datos, resolver las reglas de negocio, etc. Solo queda por hacer un front-end que obtenga los datos que se desean presentar desde el servicio web.

El webservice que usaremos de ejemplo recibe por parámetro, por ejemplo, un nombre, y devuelve "Hola + parámetro".
Por lo que nuestro cliente del webservice tiene un textbox donde ingresar el nombre, un botón para solicitar la respuesta del webservice y un label donde se mostrara la respuesta. La idea es evitar el postback al presionar el botón y mostrar el resultado en el label asíncronamente sin refrescar la página completa.

Podríamos consumir el webservice sin hacer uso de AJAX, simplemente, creando una webreference en nuestro proyecto del cliente y en el evento Click del botón hacer la llamada al webservice y setear el resultado en el label, pero esto nos implicaría un full postback de la pagina.

La solución para implementar AJAX en una llamada a un webservice es hacer uso del ASP.NET AJAX Framework, combinado con JavaScript del lado del cliente para hacer la llamada al webservice y para la actualización del label con el resultado.
Analicemos esta solución paso por paso.

Lo primero que debemos hacer es indicarle al webservice como debe responder a una llamada JavaScript. Para esto debemos primero modificar el web.config de nuestro proyecto que tiene el webservice agregándole algunas configuraciones.

<?xml version="1.0"?>

<configuration>

<configSections>

<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/>

<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere"/>

<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/>

<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/>

&nbsp; </sectionGroup>

</sectionGroup>

</sectionGroup>

</configSections>

<system.web>

<pages>

<controls>

<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</controls>

</pages>

<compilation debug="true">

<assemblies>

<add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</assemblies>

</compilation>

<httpHandlers>

<remove verb="*" path="*.asmx"/>

<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>

</httpHandlers>

<httpModules>

<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</httpModules>

</system.web>

<system.webServer>

<validation validateIntegratedModeConfiguration="false"/>

<modules>

<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</modules>

<handlers>

<remove name="WebServiceHandlerFactory-Integrated"/>

<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</handlers>

</system.webServer>

</configuration>


Este seria el web.config completo que deberíamos tener. Con este web.config nuestro webservices seguirán funcionando si los invocamos con SOAP pero también podrán ser invocados desde JavaScript.

El siguiente paso de decorar el webservice agregando lo siguiente:
[System.Web.Script.Services.ScriptService()]

El código completo del webservice nos debería haber quedado de la siguiente forma:

using System;

using System.Web;

using System.Collections;

using System.Web.Services;

using System.Web.Services.Protocols;

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.Web.Script.Services.ScriptService()]

public class SimpleService : System.Web.Services.WebService {

public SimpleService (){}

[WebMethod]

public string SayHello(String inStr) {

return "Hello : " + inStr + "; Thanks for visiting.";

}

}

Hasta este momento hemos preparado todos nuestros componentes del lado del servidor para que sean capaces de responder la llamada JavaScript que se le hará al webservice, en otras palabras, tenemos un AJAX-Enabled WebService.

Ahora debemos crear un cliente para probar este AJAX-Enabled WebService. Recordemos que no necesitamos crear una webreference.
Lo primero que debemos hacer es agregar un ScriptManager a la pagina .aspx.
El ScriptManager es un componente que forma parte de las extensiones que se agregan a ASP.NET 2.0 para crear aplicaciones AJAX.
El ScriptManager es el encargado de enviar dinámicamente el código JavaScript que el cliente necesita para realizar todas las funcionalidad que nos permite hacer el AJAX ASP.NET Framework.
El conjunto completo de componentes que tenemos disponibles cuando agregamos el ASP.NET AJAX Framework son ScriptManager, ScriptManagerProxy, Timer, UpdatePanel y UpdateProgress.

Necesitamos agregar controles, pero no vamos a utilizar controles del servidor, no son necesarios, utilizaremos controles HTML puros.
Nuestra página .aspx debería tener esta estructura:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head id="Head1" runat="server">

<title>Untitled Page</title>

</head>

<body style="text-align: center">

<form id="form1" runat="server">

<div>

<asp:ScriptManager ID="ScriptManager1" runat="server">

</asp:ScriptManager>

<input id="Text1" type="text" />

<input id="Button1" type="button" value="button"/>

<input id="Text2" type="text" />

</div>

</form>

</body>

</html>

Debemos indicarle al ScriptManager cual es el path al webservice, por lo que agregaremos el webservice a la colección de webservices del ScriptManager de la siguiente forma:

<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>

<asp:ServiceReference Path="SimpleService.asmx" />

</Services>

</asp:ScriptManager>

Ahora hemos indicado al ScriptManager que el código va a llamar a un webservice vía JavaScript, entonces el ScriptManager le solicita al servidor que le envié el código JavaScript necesario para conectarse al webservice, esto nos ahorra escribir todo el código JavaScript necesario para conectarnos a un webservices, como por ejemplo, crear a mano un objeto XmlHttpRequest y demás.

Ahora crearemos una función en JavaScript que será ejecutada en el evento onclick del botón que agregamos a nuestra pagina HTML. La llamada al webservice no se hace directamente llamando al método sino que se hace a través de un proxy. También queremos hacer esta llamada asíncrona para no tener que detener la ejecución de la aplicación hasta que el webservice nos devuelva la información que le solicitamos.
Debemos agregar código JavaScript a nuestra pagina .aspx de la siguiente forma:

<script language="javascript" type="text/javascript">

<!--

function Button1_onclick() {

ret = SimpleService.SayHello(document.getElementById('Text1').value, OnComplete, OnTimeOut, OnError);

return(true);

}

function OnComplete(args) {

document.getElementById('Text2').innerText = args;

}


function OnTimeOut(args) {

alert("Service call timed out.");

}

function OnError(args) {

alert("Error calling service method.");

}

// -->

</script>

Recordemos que no estamos llamando al método SayHello directamente sino que lo hacemos a través de un proxy que recibe algunos otros parámetros más que el string que recibe el método SayHello.
El primer parámetro es el del método SayHello, por lo cual le pasamos el contenido de la caja de texto.
El segundo parámetro es el nombre de la función JavaScript que será llamada cuando el webservice nos devuelva exitosamente la información que le solicitamos de manera asíncrona.
El tercer parámetro es el nombre de la función JavaScript que será llamada en el caso que el webservice no responda.
El cuarto parámetro es el nombre de la función JavaScript que será llamada en el caso que se produzca un error, esto significa que el webservice atendió mi petición pero no puedo responder debido a un error.

En la función OnComplete, parseamos la respuesta del webservice en nuestro caso, solamente asignamos el texto que nos envió el webservice al label donde queremos mostrar la respuesta en la página.

Por ultimo debemos agregar que función debe llamarse al ejecutarse el evento onclick del botón.
<input id="Button1" style="width: 193px" type="button" value="button" language="javascript" onclick="return Button1_onclick()" />

En este momento tendríamos el cliente que va a consumir el webservice listo.

Conclusiones

Muchas son las ventajas de utilizar este framework pero las más importantes son: implementar aplicaciones AJAX altamente performantes, reutilizar los webservice que ya tenemos creados y crear fácilmente aplicaciones ricas para el usuario mejorando la productividad y la performance.

Recursos

Para bajar el AJAX ASP.NET Framework:
http://asp.net/ajax/downloads/