ASP.NET de soporte de voz

Actualizaciones de páginas dinámicas con XMLHTTP

Para personalizar esta columna según sus necesidades, queremos invitarle a enviar sus ideas sobre temas que le interesen y sobre problemas que desea ver en futuros artículos de la Knowledge Base y columnas de soporte de voz. Puede enviar sus ideas y comentarios mediante el formulario Solicitarlo. También hay un vínculo al formulario en la parte inferior de esta columna.

INTRODUCCIÓN

Una de mis formas favoritas de estudiar la usabilidad de la aplicación web es ver a mi mujer navegar por un sitio web. Puede moverse bastante bien por Internet, pero sabe poco sobre los aspectos técnicos de bajo nivel (lo que denomina "cosas aburridas") que hacen que todo funcione.



En una noche reciente, estaba viendo a mi mujer permear una aplicación de comercio electrónico de uno de los grandes niños. Estaba desglosando en una lista de productos usando varias listas desplegables, cada una de ellas alimentando la selección realizada anteriormente. Al hacer clic en un elemento en cada lista desplegable, la página se publicó de nuevo para obtener datos para la siguiente lista desplegable. La experiencia fue frustrante para ella porque su impresión fue que tardaba mucho tiempo debido a la publicación.



El nivel de frustración que experimentaba podría haber sido fácilmente acobado por los desarrolladores de la aplicación si solo usaban XMLHTTP para recuperar los datos en lugar de publicar de nuevo. De eso trata la columna de este mes. Le mostraré cómo usar XMLHTTP para actualizar una parte de una página web con datos de un servicio web de Microsoft ASP.NET sin realizar una publicación de nuevo. ¡Esto va a estar muy bien! Confía en mí.

Información general

XMLHTTP funciona enviando una solicitud al servidor web desde el cliente y devolviendo una isla de datos XML. Según la estructura del XML que se reciba, puede usar XSLT o XML DOM para manipular y enlazar partes de la página a los datos. Esta es una técnica extremadamente eficaz.

NoteMicrosoft ofrece un comportamiento de servicio web para Internet Explorer que hace que las llamadas asincrónicas a ASP.NET web de forma rápida y sencilla. Sin embargo, este comportamiento no es compatible y no es la mejor manera de actualizar una página asincrónicamente. Debería usar XMLHTTP en su lugar.


En el ejemplo en el que trabajaré en esta columna, realizaré tres llamadas de servicio web a un servicio web de ASP.NET a través deHTTP. El servicio web realizará una consulta en la base de datos Northwind en el SQL Server local y devolverá un conjunto de datos al cliente en forma de diferencias XML. A continuación, usaré EL DOM XML para analizar los datos XML y actualizar dinámicamente partes de mi página. Todo esto se realizará sin que se vuelva a publicar.

El servicio web

El servicio web que usaré se denomina DynaProducts. Se trata de un servicio ASP.NET web 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 que se pasan al método.

  • GetProductDetails: devuelve un conjunto de datos que contiene detalles sobre el producto cuyo IdProducto se pasa al método.

La página HTML

Lo primero que puede resultarte interesante sobre este ejemplo es que la página que estoy actualizando aunque el servicio web ASP.NET web no es una ASP.NET página. Es solo una página HTML normal. Sin embargo, he agregado una gran cantidad de JavaScript del lado cliente a la página, y es ese script el que realiza las llamadas al servicio web.



Echemos un vistazo al primer fragmento de código de la página HTML.

var objHttp;
var objXmlDoc;

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

// create the XML object
objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

if (objXmlDoc == null)
{
alert("Unable to create DOM document!");

} else {

// create an XmlHttp instance
objHttp = new ActiveXObject("Microsoft.XMLHTTP");


// Create the SOAP Envelope
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>";


// Set up the post
objHttp.onreadystatechange = function(){

// a readyState of 4 means we're ready to use the data returned by XMLHTTP
if (objHttp.readyState == 4)
{

// get the return envelope
var szResponse = objHttp.responseText;

// load the return into an XML data island
objXmlDoc.loadXML(szResponse);

if (objXmlDoc.parseError.errorCode != 0) {
var xmlErr = objXmlDoc.parseError;
alert("You have 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;
}

// send the POST to the Web service
objHttp.open("POST", szUrl, true);
objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
objHttp.send(strEnvelope);
}
}

Este es el código más grande de la página y quiero re páglo en detalle para que comprendas lo que está sucediendo.



En la parte superior de este bloque de script, he creado dos variables: objHttp y objXmlDoc. Estas son las variables que usaré para mi objeto XMLHTTP y mi objeto DOM XML. Inmediatamente después está la definición de la función para la función getDataFromWS. Esta es la función responsable de realizar la llamada del cliente al servicio web. Se necesitan los cuatro argumentos siguientes, dos de los cuales son opcionales:

  • methodName: el nombre del método al que llamar en el servicio web.

  • dataSetName: nombre del conjunto de datos devuelto por el servicio web.

  • wsParamValue: el valor del parámetro que se pasa al servicio web si procede. (Opcional)

  • wsParamName: nombre del parámetro que se pasa al servicio web si procede. (Opcional)

Separaremos la función getDataFromWS por partes y hablaremos de cada una de ellas. Este es el primer fragmento:

// create the XML object
objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

if (objXmlDoc == null)
{
alert("Unable to create DOM document!");

} else {

// create an XMLHTTP instance
objHttp = new ActiveXObject("Microsoft.XMLHTTP");

Este bloque de código crea el objeto XMLHTTP y el objeto Documento XML. A continuación, empiezo a crear el sobre SOAP.

// Create the SOAP Envelope
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, estoy asignando el sobre SOAP a una variable de cadena para que pueda pasarlo al servicio web. En realidad, es bastante fácil descubrir cómo dar formato al sobre SOAP para su servicio web. Simplemente vaya al servicio web y haga clic en uno de los métodos para ver un sobre SOAP para ese método. Por ejemplo, esto es lo que veo al navegar al método GetCategories del servicio web wsXMLHTTP que he creado para este artículo:texto alternativoASP.NET le indica cómo debe dar formato al sobre SOAP para una PUBLICACIÓN HTTP y una get



http. En el ejemplo presentado en este artículo, usaré HTTP POST.



Hasta ahora, bien. Ahora vamos a ver la siguiente sección de código.

// Set up the post
objHttp.onreadystatechange = function(){

// a readyState of 4means we're ready to use thedata returned byXMLHTTP
if (objHttp.readyState == 4)
{

// getthe return envelope
varszResponse= objHttp.responseText;

// loadthe return into an XML data island
objXmlDoc.loadXML(szResponse);

if (objXmlDoc.parseError.errorCode != 0) {
var xmlErr =objXmlDoc.parseError;
alert("You have error " + xmlErr.reason);
}
else
{

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

}
}

Cuando una solicitud se realiza a través de XMLHTTP, el objeto XMLHTTP usa una propiedad readyState para realizar un seguimiento del estado de la solicitud. Cuando todos los datos se han recibido del servicio web, la propiedad readyState cambia a un valor de 4. La propiedad onreadystatechange para el objeto XMLHTTP le permite configurar una función de https que se llamará cuando cambie la propiedad readyState. Al asegurarme de que los datos se han recibido en su totalidad, puedo seguir actuando con los datos hasta que esté listo.



Una vez que se han recibido todos los datos, creo una isla de datos XML con la respuesta mediante la propiedad responseText. Como sabrá, la respuesta de un servicio web está en formato XML. En este caso, devolveré un conjunto de datos de Microsoft ADO.NET Datos.



La siguiente sección de este bloque de código usa una instrucción Switch para llamar a la función adecuada basándose en el nombre del conjunto de datos devuelto desde el servicio web. Voy al código de esas funciones un poco más adelante.


Ahora vamos a ver el código que ejecuta realmente la solicitud XMLHTTP.

var szUrl;
szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;

if (wsParamValue != null)
{

szUrl += "?" + wsParamName + "=" + wsParamValue;
}

// send the POST to the Web service
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 que se usa para llamar al servicio web en nombre de la claridad. A continuación, tengo una instrucción if que contrae cualquier parámetro que se pasa como un valor de QueryString. En su entorno, es posible que desee agregar los parámetros al sobre SOAP. En ambos casos funcionará correctamente.



El método de apertura del objeto XMLHTTP se denomina siguiente. He usado los tres primeros argumentos para el método abierto; el método, la dirección URL y un valor booleano que especifica si la llamada es asíncrona o no.
Importante Si está realizando una llamada asíncrona tal como estoy aquí, debe configurar una función descrónico a través de la propiedad onreadystatechanged.

Después de establecer el encabezado de la solicitud para el tipo de contenido, envío la solicitud como sobre SOAP con la variable de cadena que he rellenado anteriormente.



Ya hemos pasado por todo el código que hace que la solicitud XMLHTTP. Ahora echemos un vistazo al código que controla la interfaz en el explorador y que controla la respuesta de la llamada del servicio web.

En primer lugar, miraremos la función que se llama cuando se carga la página por primera vez.

function getCategories()
{

var func = "getDataFromWS('GetCategories', 'CategoriesDS')";
document.all.lblCategoryDropdown.innerText =
"Please wait while data is retrieved...";
window.setTimeout(func, 1);

}

Lo primero que hago en esta función es crear una variable para almacenar la firma de la 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 método es permitirme mostrar el estado al usuario mientras espera a que se complete la llamada del servicio web. Observe que estoy cambiando el texto interno de una DIV para mostrar un mensaje que indica que se recuperan datos. A continuación, programo la función getDataFromWS a través de la llamada window.setTimeout y la he configurado para ejecutarla en un milisegundo.

Procesamiento de la respuesta del servicio web

Recuerde que antes usé la propiedad onreadystatechanged para configurar una función de adesa. Además, recuerde que la función de conjunto de datos contiene una instrucción switch que llama a una función determinada basándose en el nombre del conjunto de datos. En este caso, el nombre del conjunto de datos es CategoriesDS. Por lo tanto, la función processCategory se denominará desde la función category. Echemos un vistazo a esa función para ver cómo usar el DOM XML para analizar la respuesta del servicio web.

function processCategory()
{

// get an XML data island with the category data
objNodeList = objXmlDoc.getElementsByTagName("Categories");

// add default value to the drop-down
document.forms[0].drpCategory.options[0] = new Option("Select a Category", 0);

// walk through the nodeList and populate the drop-down
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 = "Select a Category:";
document.forms[0].drpCategory.style.visibility = "visible";

}

}

Recuerde que la función getDataFromWS ha cargado XML de la respuesta en el objeto objXmlDoc. En la función processCategory, tomo ese XML y lo voy analizando para rellenar la lista desplegable Categoría.



Lo primero que hago es crear un objeto IXMLDOMNodeList con parte de la respuesta XML. El conjunto de datos que estoy volviendo de la llamada del servicio web se devuelve como un diferencia, y la única parte de esa respuesta que me interesa realmente son los datos de la tabla de datos que he insertado en el conjunto de datos. Puedo llegar a esto creando un objeto IXMLDOMNodeList desde el bloque XML que contiene la tabla Datos.



Si mira el código del servicio web, verá que creo una tabla de datos con el nombre Categorías y la añado al conjunto de datos. Cuando se devuelve el XML desde el servicio web, el conjunto de datos se incluye dentro de un bloque> Categorías <y cada fila de la tabla de datos se incluye en bloques> independientes de <Categories, tal como se muestra en el archivo XML siguiente.

Los siguientes archivos están disponibles para su descarga desde el Centro de descarga de Microsoft:Descargar
descargar GetCategories.xml paquete ahora.
Descargar Descargar el WSXMLHTTP.exe ahora.Para obtener más información sobre cómo descargar archivos de soporte técnico de Microsoft, haga clic en el siguiente número de artículo para ver el artículo en Microsoft Knowledge Base:

119591 Cómo obtener archivos de soporte técnico de Microsoft de los servicios en línea que Microsoft ha examinado
en busca de virus. Microsoft usó el software de detección de virus más reciente que había disponible en la fecha en la que se publicó el archivo. El archivo está guardado en servidores de seguridad mejorada que ayudan a prevenir cambios no autorizados del archivo.


Para obtener el bloque XML que contiene esa tabla de datos, uso el código siguiente:

objNodeList = objXmlDoc.getElementsByTagName("Categories");

Devuelve un objeto IXMLDOMNodeList que contiene cada <categorías> nodo. A continuación, reojo en iteración por esa lista mediante un bucle for.

// walk through the nodeList and populate the drop-down
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 = "Select a Category:";
document.forms[0].drpCategory.style.visibility = "visible";

}

Ya sé que cada nodo <categorías> va> dos nodos que necesito: el nodo de <Id.> y el nodo <categoryname> nodo. Por lo tanto, lo primero que hago es crear un nuevo IXMLDOMNodeList y rellenarlo con los nodos secundarios del nodo <categorías> actual.

dataNodeList = objNodeList[i].childNodes;

A continuación, uso el método del elemento para obtener acceso a los dos nodos que necesito rellenar en la lista desplegable. El primer nodo contiene el campo IdDe Category de la base de datos y el segundo nodo contiene el campo CategoryName de la base de datos. Creo un nuevo objeto Option, establece el texto en CategoryName, establece el valor en CategoryID y lo agrego a la lista desplegable drpCategory. El código que se usa en las funciones restantes usa el mismo método para extraer los datos necesarios de la respuesta XML y rellenar partes de la página.

Tenga en cuenta que estamos tratando con pequeñas cantidades de datos aquí, usar DOM es una buena forma de extraer los datos que necesitamos. Si estaba tratando con una gran cantidad de datos, puede elegir usar XSLT en su lugar.

Cómo hacer que todo funcione

Ahora que he cubierto los detalles detalladamente de cómo funciona todo esto, es el momento de reespón de cómo puede usar los archivos de ejemplo incluidos para ver cómo funciona para usted mismo.

Implementar el servicio web

Para implementar la aplicación ASP.NET web, simplemente descomprima la muestra de 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, tendrá que escribir la contraseña de sa. Una vez que haya realizado el 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 al servicio web. Encontrará esta variable en la función getDataFromWS cerca de la parte inferior de la función. Tendrá que cambiarlo por la dirección URL del servicio web que implementó anteriormente.


Después de implementar el servicio web y el archivo HTML, busque el archivo HTML. Cuando se cargue, la lista desplegable Categoría se rellenará con la primera solicitud XMLHTTP al servicio web. Una vez rellenado, seleccione una categoría para iniciar la siguiente 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 se publica durante ninguna de estas solicitudes XMLHTTP. Esa es la belleza 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" en el usuario. Si me lo pregunta, es algo muy eficaz.



Algo más: en este artículo, usé XMLHTTP para consultar un servicio web. Podría haberla usado tan fácilmente para realizar una solicitud de una página ASPX o una página ASP. Las posibilidades para poner esta tecnología en uso son infinitas. Espero que encuentre XMLHTTP útil en el desarrollo futuro de aplicaciones web.

Como siempre, no dude en enviar ideas sobre temas que desea tratar en futuras columnas o en Microsoft Knowledge Base mediante el formulario Preguntar.

¿Necesita más ayuda?

Ampliar sus conocimientos
Explorar los cursos
Obtener nuevas características primero
Unirse a Microsoft Insider

¿Le ha sido útil esta información?

¿Cuál es tu grado de satisfacción con la calidad del lenguaje?
¿Qué ha afectado a tu experiencia?

¡Gracias por sus comentarios!

×