Actualizaciones de páginas dinámicas con XMLHTTP

Seleccione idioma Seleccione idioma
Id. de artículo: 893659 - Ver los productos a los que se aplica este artículo
Columna de ASP.NET Support Voice

Actualizaciones de páginas dinámicas con XMLHTTP

Para adaptar esta columna a sus necesidades, deseamos invitarle a que envíe sus ideas sobre temas de su interés y los problemas que desea que se traten en futuros artículos de Knowledge Base y columnas de Support Voice. Puede enviar sus ideas y comentarios mediante el formulario Ask For It. Hay también un vínculo al formulario en la parte inferior de esta columna.
Expandir todo | Contraer todo

En esta página

INTRODUCCIÓN

Una de mis maneras favoritas de estudiar la facilidad de uso de las aplicaciones Web es observar cómo mi esposa se desplaza por un sitio Web. Se mueve bastante bien en Internet, pero sabe poco sobre los aspectos técnicos básicos (que, según ella, son "eso tan aburrido") que permiten su funcionamiento.

Hace poco, estaba observando cómo mi esposa usaba una aplicación de comercio electrónico de una gran compañía. Estaba viendo los detalles de una lista de productos con varias listas desplegables, cada una de las cuales se extraía de la selección realizada previamente. Cuando hacía clic en un elemento en cada lista desplegable, la página volvía a obtener los datos de la siguiente lista desplegable. La experiencia le resultaba frustrante porque daba la impresión de que llevaba mucho tiempo debido a las devoluciones.

Los desarrolladores de la aplicación podrían aliviar fácilmente el nivel de frustración que estaba experimentando si utilizaran XMLHTTP, en lugar de devoluciones, para recuperar los datos. De esto es lo que trata la columna de este mes. Le mostraré cómo utilizar XMLHTTP para actualizar una parte de una página Web con datos de un servicio Web de Microsoft ASP.NET sin realizar devoluciones. Será muy interesante. Confíe en mí.

Información general

XMLHTTP envía una solicitud al servidor Web desde el cliente y devuelve una isla de datos XML. Según la estructura XML que se reciba, puede utilizar XSLT o XML DOM para manipularla y enlazar partes de la página a esos datos. Ésta es una técnica sumamente eficaz.

Nota
Microsoft ofrece un comportamiento de Servicio Web para Internet Explorer que realiza llamadas asincrónicas a los servicios Web ASP.NET rápida y fácilmente. Sin embargo, no se admite este comportamiento y no es la mejor manera de actualizar asincrónicamente una página. Debe utilizar en su lugar XMLHTTP.

En el ejemplo que explicaré en esta columna, realizaré tres llamadas del servicio Web a un servicio Web ASP.NET a través de XMLHTTP. El servicio Web consultará la base de datos Northwind en el servidor SQL Server local y devolverá un conjunto de datos al cliente en forma de diffgram de XML. A continuación, utilizaré XML DOM para analizar los datos XML y actualizar dinámicamente partes de mi página. Todo esto se hará sin ninguna devolución.

El servicio Web

El servicio Web que utilizaré se denomina DynaProducts. Es un servicio Web ASP.NET básico escrito en C# que contiene los tres métodos siguientes.
  • GetCategories: devuelve un conjunto de datos que contiene todas las categorías de la tabla Categorías.
  • GetProducts: devuelve un conjunto de datos que contiene todos los productos de la categoría pasada al método.
  • GetProductDetails: devuelve un conjunto de datos que contiene los detalles del producto cuyo ProductID se pasa al método.

La pagina HTML

Lo primero que llamará su atención en este ejemplo es que la página que estoy actualizando a través del servicio Web ASP.NET no es una página ASP.NET. Simplemente es una página HTML normal. Sin embargo, he agregado algo de código JavaScript del cliente a la página; esa secuencia de comandos es la que realiza las llamadas al servicio Web.

Examinemos el primer fragmento de código de la página HTML.
var objHttp; var objXmlDoc;

function getDataFromWS(methodName, dataSetName, wsParamValue, wsParamName) {

    // crear el objeto XML objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null) { alert("No se puede crear el documento DOM");
        
    } else {

	    // crear una instancia XmlHttp objHttp = new ActiveXObject("Microsoft.XMLHTTP");
	
	
	    // Crear la envoltura SOAP strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
	            " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
	            " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
	            "  <soap:Body>" +
	
	            "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
	            "    </" + methodName + ">" +
	
	            "  </soap:Body>" +
	
	            "</soap:Envelope>";
	
	
	    // Configurar el envío objHttp.onreadystatechange = function(){
	
	        // un readyState de 4 significa que estamos listos para utilizar los datos devueltos por XMLHTTP if (objHttp.readyState == 4) {
	
	            // obtener la envoltura devuelta var szResponse = objHttp.responseText;
							
	            // cargar los datos devueltos en una isla de datos XML objXmlDoc.loadXML (szResponse);
	
	            if (objXmlDoc.parseError.errorCode != 0) { var xmlErr = objXmlDoc.parseError; alert("Ha ocurrido el error " + xmlErr.reason); } else {
	
	                switch(dataSetName) { case "CategoriesDS": processCategory(); break;
	
	                    case "ProductsDS": processProducts(); break;
	
	                    case "ProductDetailDS": processProductDetails(); break;
	
	                } }
	
	        } }
	
	    var szUrl; szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	    if (wsParamValue != null) {
	
	        szUrl += "?" + wsParamName + "=" + wsParamValue; }
	
	    // enviar POST al servicio Web objHttp.open("POST", szUrl, true); objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); objHttp.send(strEnvelope); } }
Éste es el fragmento más grande de código de la página y deseo revisarlo en detalle para que entienda bien su funcionamiento.

En la parte superior de este bloque de secuencias de comandos, creé dos variables: objHttp y objXmlDoc. Éstas son las variables que utilizaré para los objetos XMLHTTP y XML DOM, respectivamente. Justo después de eso está la definición de la función getDataFromWS. Ésta es la función responsable de realizar la llamada del cliente al servicio Web. Toma los cuatro argumentos siguientes, dos de los cuales son opcionales:
  • methodName: nombre del método para llamar al servicio Web.
  • dataSetName: nombre del conjunto de datos devuelto por el servicio Web.
  • wsParamValue: valor del parámetro pasado al servicio Web si corresponde. (Opcional)
  • wsParamName: nombre del parámetro pasado al servicio Web si corresponde. (Opcional)
Dividamos la función getDataFromWS en partes para describir cada una de ellas. Éste es el primer fragmento de código:
// crear el objeto XML objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null) { alert("No se puede crear el documento DOM");

    } else {

		// crear una instancia de XMLHTTP objHttp = new ActiveXObject("Microsoft.XMLHTTP"); 
Este bloque de código crea el objeto XMLHTTP y el objeto Documento XML. Después, empiezo a crear la envoltura SOAP.
// Crear la envoltura SOAP strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
          " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
          " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
          "  <soap:Body>" +
	
          "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
          "    </" + methodName + ">" +
	
          "  </soap:Body>" +
	
          "</soap:Envelope>"; 
En este código, voy a asignar la envoltura SOAP a una variable de cadena para poder pasarla al servicio Web. Realmente es bastante fácil descubrir cómo dar formato a la envoltura SOAP para el servicio Web. Simplemente vaya al servicio Web y haga clic en uno de los métodos para ver una envoltura SOAP de ese método. Por ejemplo, esto es lo que se ve al desplazarse al método GetCategories del servicio Web wsXMLHTTP que creé para este artículo:

Contraer esta imagenAmpliar esta imagen
envelope.png


ASP.NET le indica cómo se debe dar formato a la envoltura SOAP para los métodos HTTP POST y HTTP GET. En el ejemplo presentado en este artículo, utilizaré HTTP POST.

Por ahora, todo va bien. Ahora examinemos la siguiente sección de código.
// Configurar el envío objHttp.onreadystatechange = function(){
	
// un readyState de 4	significa que estamos listos para utilizar	los datos devueltos por	XMLHTTP if (objHttp.readyState == 4) {
	
		// obtener	la envoltura devuelta var	szResponse	= objHttp.responseText;
	
		   // cargar	los datos devueltos en una isla de datos XML objXmlDoc.loadXML (szResponse);
	
		   if (objXmlDoc.parseError.errorCode != 0) { var xmlErr =	objXmlDoc.parseError; alert("Ha ocurrido el error " + xmlErr.reason); } else {

		switch(dataSetName) { case "CategoriesDS": processCategory(); break; case "ProductsDS": processProducts(); break; case "ProductDetailDS": processProductDetails(); break;

				} } 
Cuando se realiza una solicitud a través de XMLHTTP, el objeto XMLHTTP utiliza una propiedad readyState para realizar el seguimiento del estado de la solicitud. Cuando se han recibido todos los datos del servicio Web, la propiedad readyState cambia a un valor de 4. La propiedad onreadystatechange del objeto XMLHTTP permite configurar una función de devolución de llamada a la que se llamará cuando la propiedad readyState cambie. Al garantizar que los datos se han recibido en su totalidad, puedo impedir que se actúe sobre ellos hasta que esté listo.

Una vez recibidos todos los datos, creo una isla de datos XML con la respuesta utilizando la propiedad responseText. Como probablemente sepa, la respuesta de un servicio Web está en formato XML. En este caso, voy a devolver un conjunto de datos de Microsoft ADO.NET.

La próxima sección de este bloque de código utiliza una instrucción de modificador para llamar a la función adecuada según el nombre del conjunto de datos devuelto por el servicio Web. Comentaré detalladamente el código de esas funciones un poco más adelante.

Examinemos ahora el código que realiza realmente la solicitud XMLHTTP.
var szUrl; szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	if (wsParamValue != null) {
	
	      	szUrl += "?" + wsParamName + "=" + wsParamValue; }
	
// enviar POST al servicio Web objHttp.open("POST", szUrl, true); objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); objHttp.send(strEnvelope); 
La variable szUrl contiene la dirección URL utilizada para llamar al servicio Web para mayor claridad. A continuación hay una instrucción if que establece los parámetros que se pasan como un valor QueryString. En su entorno, puede ser conveniente agregar los parámetros a la envoltura SOAP. De cualquier modo funcionará igualmente bien.

Después se llama al método open del objeto XMLHTTP. He utilizado los tres primeros argumentos del método open: el método, la dirección URL y un valor booleano que especifica si la llamada es asincrónica o no.
Importante
Si va a realizar una llamada asincrónica como estoy haciendo aquí, debe configurar una función de devolución de llamada mediante la propiedad onreadystatechanged.

Después de establecer el encabezado de solicitud para el tipo de contenido, envío la solicitud como una envoltura SOAP mediante la variable de cadena que rellené anteriormente.

Hemos revisado todo el código que compone la solicitud XMLHTTP. Veamos ahora el código que controla la interfaz en el explorador y la respuesta de la llamada al servicio Web.

En primer lugar veremos la función a la que se llama cuando se carga la página por primera vez.
function getCategories() {

  var func = "getDataFromWS('GetCategories', 'CategoriesDS')"; document.all.lblCategoryDropdown.innerText = "Espere mientras se recuperan los datos..."; window.setTimeout(func, 1);

  } 
Lo primero que hago en esta función es crear una variable para almacenar la firma de función para getDataFromWS. Hago esto porque voy a llamar a window.setTimeout al final de esta función para llamar a la función getDataFromWS. El propósito de este enfoque es permitirme mostrar el estado al usuario mientras espero a que la llamada al servicio Web finalice. Observe que estoy cambiando innerText de DIV para mostrar un mensaje que indica que se están recuperando los datos. Después programo la función getDataFromWS a través de la llamada window.setTimeout y la establezco para que se ejecute en un milisegundo.

Procesamiento de la respuesta del servicio Web

Recuerde que anteriormente utilicé la propiedad onreadystatechanged para configurar una función de devolución de llamada. Recuerde también que la función de devolución de llamada contiene una instrucción de modificador que llama a una función determinada según el nombre del conjunto de datos. En este caso, nuestro nombre de conjunto de datos es CategoriesDS. Por tanto, se llamará a la función processCategory desde la función de devolución de llamada. Examinemos esa función para ver cómo utilizar XML DOM para analizar la respuesta del servicio Web.
function processCategory() {

  // obtener una isla de datos XML con los datos de categoría objNodeList = objXmlDoc.getElementsByTagName ("Categorías");
 
  // agregar el valor predeterminado a la lista desplegable document.forms[0].drpCategory.options[0] = new Option("Seleccione una categoría", 0);

  // recorrer nodeList y rellenar la lista desplegable for (var i = 0; i < objNodeList.length; i++) { var dataNodeList; var textNode; var valueNode;

      dataNodeList = objNodeList[i].childNodes; valueNode = dataNodeList.item(0); textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = new Option(textNode.text, valueNode.text); document.all.lblCategoryDropdown.innerText = "Seleccione una categoría:"; document.forms[0].drpCategory.style.visibility = "visible";
       
    }

  } 
Recuerde que la función getDataFromWS cargó el contenido XML de la respuesta en el objeto objXmlDoc. En la función processCategory, tomo ese contenido XML y lo analizo para rellenar la lista desplegable Categoría.

Lo primero que hago es crear un objeto IXMLDOMNodeList mediante una parte de la respuesta XML. El conjunto de datos que estoy devolviendo de la llamada al servicio Web se devuelve como diffgram y la única parte de interés de esa respuesta son los datos de DataTable que he insertado en el conjunto de datos. Puedo lograr esto si creo un objeto IXMLDOMNodeList a partir del bloque XML que contiene DataTable.

Si examina el código del servicio Web, verá que creo un objeto DataTable denominado Categorías y lo agrego al conjunto de datos. Cuando se devuelve contenido XML del servicio Web, el conjunto de datos se incluye en un bloque <CategoriesDS> y cada fila de DataTable se incluye en bloques <Categories> diferentes como se muestra en el archivo XML siguiente.

Los archivos siguientes pueden descargarse desde el Centro de descarga de Microsoft:
Contraer esta imagenAmpliar esta imagen
Descargar
Descargue el paquete GetCategories.xml ahora.
Contraer esta imagenAmpliar esta imagen
Descargar
Descargue el paquete WSXMLHTTP.exe ahora. Para obtener más información acerca de cómo descargar los archivos de soporte técnico de Microsoft, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:
119591 Cómo obtener archivos de soporte técnico de Microsoft desde los servicios en línea
Microsoft exploró este archivo en busca de virus con el software de detección de virus más reciente disponible en la fecha de publicación. Asimismo, el archivo se almacenó en servidores seguros que ayudan a impedir la realización de cambios no autorizados.

Para obtener el bloque XML que contiene DataTable, utilizo el código siguiente:
objNodeList = objXmlDoc.getElementsByTagName("Categorías");
Esto devuelve un objeto IXMLDOMNodeList que contiene cada nodo <Categories>. Después recorro en iteración esa lista utilizando un bucle for.
// recorrer nodeList y rellenar la lista desplegable for (var i = 0; i < objNodeList.length; i++) { var dataNodeList; var textNode; var valueNode;

      dataNodeList = objNodeList[i].childNodes; valueNode = dataNodeList.item(0); textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = new Option(textNode.text, valueNode.text); document.all.lblCategoryDropdown.innerText = "Seleccione una categoría:"; document.forms[0].drpCategory.style.visibility = "visible";
       
    } 
Ya sé que cada nodo <Categories> tendrá dos nodos que necesito: el nodo <ID> y el nodo <CategoryName>. Por tanto, lo primero que hago es crear un nuevo IXMLDOMNodeList y rellenarlo con los nodos secundarios del nodo <Categories> actual.
dataNodeList = objNodeList[i].childNodes;
Después utilizo el método item para tener acceso a los dos nodos que necesito para rellenar la lista desplegable. El primer nodo contiene el campo CategoryID de la base de datos y el segundo nodo contiene el campo CategoryName de la base de datos. Creo un nuevo objeto Option, establezco el texto en CategoryName, establezco el valor en CategoryID y lo agrego a la lista desplegable drpCategory. El código utilizado en las funciones restantes emplea el mismo método para extraer los datos necesarios de la respuesta XML y rellenar partes de la página.

Nota
Como aquí estamos tratando cantidades pequeñas de datos, utilizar DOM es una manera excelente de extraer los datos que necesitamos. Si estuviera tratando una gran cantidad de datos, podría utilizar en su lugar XSLT.

Cómo hacer que todo funcione

Ahora que he tratado los detalles más técnicos de cómo funciona todo esto, es el momento de ver cómo utilizar los archivos de ejemplo incluidos para verlo funcionar.

Implementar el servicio Web

Para implementar el servicio Web ASP.NET, descomprima el ejemplo del servicio Web adjunto en la raíz de su servidor Web. A continuación tendrá que abrir el código de DynaProducts.asmx y cambiar la cadena de conexión. Como mínimo, necesitará escribir la contraseña de SA. Después de haber realizado ese cambio, vuelva a compilar el servicio Web.

Implementar el archivo HTML

El archivo HTML contiene una variable denominada szUrl que contiene una dirección URL para el servicio Web. Encontrará esta variable en la función getDataFromWS junto a la parte inferior de la función. Necesitará cambiarla por la dirección URL del servicio Web que implementó anteriormente.

Después de haber implementado el servicio Web y el archivo HTML, vaya al archivo HTML. Cuando se cargue, la lista desplegable Categoría se rellenará con la primera solicitud XMLHTTP al servicio Web. Una vez rellena, seleccione una categoría para extraer la próxima solicitud XMLHTTP que rellena la lista desplegable Productos. Al seleccionar un producto en la lista desplegable Productos, se rellenará una tabla con datos sobre ese producto.

Observe que la página no realiza devoluciones durante ninguna de estas solicitudes XMLHTTP. Ésa es la ventaja de las solicitudes XMLHTTP. Si hubiera hecho esto en una página grande, la página también habría mantenido su posición de desplazamiento sin "parpadear" al usuario. En mi opinión, es un método realmente eficaz.

Una cosa más: en este artículo, utilicé XMLHTTP para consultar un servicio Web. Igualmente podría haberlo utilizado con facilidad para realizar una solicitud de una página ASPX o una página ASP. Las posibilidades de utilización de esta tecnología son interminables. Espero que encuentre XMLHTTP útil para el desarrollo de aplicaciones Web en el futuro.
Como siempre, siéntase libre para enviar ideas sobre los temas que desee que se traten en columnas futuras o en Microsoft Knowledge Base utilizando el formulario Ask For It.

Propiedades

Id. de artículo: 893659 - Última revisión: martes, 23 de mayo de 2006 - Versión: 5.2
La información de este artículo se refiere a:
  • Microsoft ASP.NET 1.0
  • Microsoft ASP.NET 1.1
Palabras clave: 
kbgraphic kbscript kbxml kbhowto KB893659

Enviar comentarios

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com