coluna de voz de suporte ASP.NET

Atualizações dinâmicas de página usando XMLHTTP

Para personalizar esta coluna às suas necessidades, queremos convidá-lo a submeter as suas ideias sobre temas que lhe interessam e questões que pretende ver abordadas em futuros artigos da Base de Conhecimento e colunas de Voz de Suporte. Pode submeter as suas ideias e feedback utilizando o formulário Ask For It. Há também uma ligação com a forma na parte inferior desta coluna.

INTRODUÇÃO

Uma das minhas formas favoritas de estudar a usabilidade da aplicação web é ver a minha mulher navegar em torno de um site. Ela pode dar a volta à Internet muito bem, mas sabe pouco sobre os aspetos técnicos de baixo nível (o que ela chama de "coisa aborrecida") que fazem com que tudo funcione. Numa noite recente, estava a ver a minha mulher a ler uma aplicação de e-commerce de um dos grandalhões. Ela estava a perfurar uma lista de produtos usando várias gotas, cada uma alimentando-se da seleção feita anteriormente. Ao clicar num item em cada drop-down, a página publicou de volta para obter dados para a próxima entrega. A experiência foi frustrante para ela porque a sua impressão era que estava a demorar muito tempo devido às costas dos posts. O nível de frustração que ela estava a sentir poderia ter sido facilmente aliviado pelos desenvolvedores da aplicação se apenas usassem XMLHTTP para recuperar os dados em vez de voltar a publicar. É disso que se trata a coluna deste mês. Vou mostrar-lhe como usar o XMLHTTP para atualizar uma parte de uma página Web com dados de um serviço Web microsoft ASP.NET sem fazer uma publicação. Isto vai ser muito fixe! Confia em mim.

Visão geral

A XMLHTTP funciona enviando um pedido ao servidor Web do cliente e devolvendo uma ilha de dados XML. Dependendo da estrutura do XML que é recebido, pode utilizar xSLT ou o XML DOM para manipulá-lo e ligar partes da página a esses dados. Esta é uma técnica extremamente poderosa. O NoteMicrosoft oferece um comportamento de Serviço Web para o Internet Explorer que faz chamadas assíncronas para ASP.NET serviços Web de forma rápida e fácil. No entanto, este comportamento não é suportado e não é a melhor maneira de atualizar uma página assíncroneamente. Em vez disso, deve utilizar o XMLHTTP! No exemplo que vou trabalhar nesta coluna, farei três chamadas de serviço Web para um serviço Web ASP.NET através do XMLHTTP. O serviço Web consultará a base de dados Northwind no SqL Server local e devolverá um DataSet ao cliente sob a forma de um difusão XML. Em seguida, utilizarei o XML DOM para analisar os dados XML e atualizar dinamicamente partes da minha página. Tudo isto será feito sem um poste de volta.

O serviço web

O serviço web que vou usar chama-se DynaProducts. É um serviço Web ASP.NET básico que está escrito em C# e que contém os três métodos seguintes.

  • GetCategories – Devolve um DataSet que contém todas as categorias na tabela Categorias.

  • GetProducts – Devolve um DataSet que contém todos os produtos da categoria que são passados para o método.

  • GetProductDetails – Devolve um DataSet que contém detalhes sobre o produto cujo ProdutoID é passado para o método.

A página HTML

A primeira coisa que pode atacá-lo sobre esta amostra é que a página que estou atualizando embora o serviço web ASP.NET não seja uma página ASP.NET. É apenas uma página html regular. No entanto, adicionei uma boa quantidade de JavaScript do lado do cliente à página, e é esse script que faz as chamadas para o serviço Web.Vejamos o primeiro corte de código da 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 é o maior código da página, e quero vê-lo em detalhe para que percebas o que se está a passar.No topo deste bloco de scripts, criei duas variáveis: objHttp e objXmlDoc. Estas são as variáveis que vou usar para o meu objeto XMLHTTP e para o meu objeto XML DOM. Imediatamente a seguir é a definição de função para a função getDataFromWS. Esta é a função que é responsável por fazer a chamada do lado do cliente para o serviço Web. São os seguintes quatro argumentos, dois dos quais opcionais:

  • métodoName – O nome do método para ligar no serviço Web.

  • dataSetName – O nome do DataSet que é devolvido pelo serviço Web.

  • wsParamValue – O valor do parâmetro que é passado para o serviço Web se aplicável. (Opcional)

  • wsParamName – O nome do parâmetro que é passado para o serviço Web se aplicável. (Opcional)

Vamos dividir a função getDataFromWS em partes e discutir cada uma delas. Aqui está o primeiro corte:

// create the XML object    objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");    if (objXmlDoc == null)    {    alert("Unable to create DOM document!");    } else {// create an XMLHTTP instanceobjHttp = new ActiveXObject("Microsoft.XMLHTTP");

Este bloco de código cria o objeto XMLHTTP e o objeto XML Document. Em seguida, começo a criar o envelope SOAP.

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

Neste código, estou a atribuir o envelope SOAP a uma variável de cadeia para que eu possa passá-lo para o serviço Web. Na verdade, é muito fácil descobrir como formatar o envelope SOAP para o seu serviço Web. Basta navegar no serviço Web e clicar num dos métodos para ver um envelope SOAP para esse método. Por exemplo, aqui está o que vejo ao navegar para o método GetCategories do serviço web wsXMLHTTP que criei para este artigo: texto alternativoASP.NET lhe diz como o envelope SOAP deve ser formatado para um HTTP POST e um HTTP GET. No exemplo apresentado neste artigo, utilizarei HTTP POST. Até aqui, tudo bem. Agora vamos ver a próxima secção de código.

// Set up the postobjHttp.onreadystatechange = function(){// a readyState of 4means we're ready to use thedata returned byXMLHTTPif (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;}}

Quando um pedido é feito através de XMLHTTP, o objeto XMLHTTP utiliza uma propriedade readyState para rastrear o estado do pedido. Quando todos os dados foram recebidos de volta do serviço Web, a propriedade readyState muda para um valor de 4. A propriedade onreadystatechange para o objeto XMLHTTP permite-lhe configurar uma função de retorno que será chamada quando a propriedade readyState mudar. Garantindo que os dados foram recebidos na sua totalidade, posso evitar agir sobre esses dados até estar pronto.Uma vez recebidos todos os dados, crio uma ilha de dados XML com a resposta utilizando a propriedade responseText. Como provavelmente sabe, a resposta de um serviço Web está no formato XML. Neste caso, estou a devolver um Microsoft ADO.NET DataSet. A próxima secção deste bloco de código utiliza uma declaração de comutação para ligar para a função adequada com base no nome do DataSet que é devolvido do serviço Web. Vou entrar no código para essas funções em detalhe um pouco mais tarde.Agora vamos olhar para o código que realmente executa o pedido XMLHTTP.

var szUrl;szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;if (wsParamValue != null){      szUrl += "?" + wsParamName + "=" + wsParamValue;}// send the POST to the Web serviceobjHttp.open("POST", szUrl, true);objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");objHttp.send(strEnvelope);

O szUrl variável contém o URL que é usado para chamar o serviço Web por uma questão de clareza. Em seguida, tenho uma afirmação que aborda quaisquer parâmetros que são passados como um valor queryString. No seu ambiente, pode querer adicionar os parâmetros ao envelope SOAP. De qualquer forma, vai funcionar muito bem.O método aberto do objeto XMLHTTP é chamado em seguida. Usei os três primeiros argumentos para o método aberto; o método, o URL e um valor Boolean que especifica se a chamada é ou não assíncronea. Importante Se você está fazendo uma chamada assíncronea como eu estou aqui, você deve configurar uma função de retorno através da propriedade onreadystate alterada. Depois de definido o cabeçalho de pedido para o tipo de conteúdo, envio o pedido como um envelope SOAP usando a variável de corda que povoei anteriormente. Já verificámos todo o código que faz o pedido do XMLHTTP. Agora vamos ver o código que trata da interface no navegador e que lida com a resposta a partir da chamada de serviço Web.Primeiro vamos olhar para a função que é chamada quando a página primeira carrega.

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

A primeira coisa que faço nesta função é criar uma variável para armazenar a assinatura de função para obterDataFromWS. Faço isto porque vou chamar janela.setTimeout no final desta função para chamar a função getDataFromWS. O objetivo desta abordagem é permitir-me mostrar o estado ao utilizador enquanto espero que a chamada de serviço Web esteja concluída. Note que estou a mudar o texto interno de um DIV para mostrar uma mensagem indicando que os dados estão a ser recuperados. Em seguida, agendei a função getDataFromWS através da chamada de tempo de janela.setTimeout, e descrevo-a para funcionar num milésimo de segundo.

Processamento da resposta do serviço Web

Lembre-se que usei a propriedade onreadystateed para configurar uma função de retorno. Lembre-se também que a função de retorno contém uma declaração de comutação que chama uma determinada função com base no nome DataSet. Neste caso, o nosso nome DataSet é CategoriesDS. Portanto, a função processCategory será chamada da função de retorno. Vamos ver esta função para ver como usar o XML DOM para analisar a resposta do serviço 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";    }  }

Lembre-se que a função GetDataFromWS carregou XML da resposta para o objeto objXmlDoc. No processo, tomo esse XML e parseei através dele para povoar a categoria de down-down.A primeira coisa que faço é criar um objeto IXMLDOMNodeList usando parte da resposta XML. O DataSet que estou a devolver da chamada de serviço Web é devolvido como um diffgram, e a única parte dessa resposta que realmente me interessa são os dados da DataTable que inseri no DataSet. Posso chegar a isso criando um objeto IXMLDOMNodeList a partir do bloco XML que contém a DataTable.Se olhar para o código do serviço Web, verá que crio uma DataTable que é denominada Categorias e adicioná-lo ao DataSet. Quando o XML é devolvido do serviço Web, o DataSet é contido num bloco <CategoriesDS>, e cada linha da DataTable está contida dentro de <categorias separadas> blocos como mostrado no ficheiro XML abaixo.Os seguintes ficheiros estão disponíveis para download a partir do Microsoft Download Center: Transferir Descarregue já o pacote GetCategories.xml. Transferir Descarregue já o pacote de WSXMLHTTP.exe.Para obter mais informações sobre como descarregar ficheiros do Microsoft Support, clique no seguinte número de artigo para ver o artigo na Base de Conhecimento da Microsoft:

119591 Como obter ficheiros de suporte da Microsoft a partir de serviços online A Microsoft digitalizou este ficheiro para vírus. A Microsoft usou o software de deteção de vírus mais atual que estava disponível na data em que o ficheiro foi publicado. O ficheiro é armazenado em servidores melhorados por segurança que ajudam a evitar quaisquer alterações não autorizadas no ficheiro.Para obter o bloco XML que contém a DataTable, uso o seguinte código:

objNodeList = objXmlDoc.getElementsByTagName("Categories");

Isto devolve um objeto IXMLDOMNodeList que contém cada <categorias> nó. Depois iterei através dessa lista usando um loop.

// 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";    }

Já sei que cada <categorias> nó terá dois nós de que preciso: o nó de <id> e o nó> de categoria <. Portanto, a primeira coisa que faço é criar um novo IXMLDOMNodeList e povoá-lo com os nós infantis das atuais categorias de <> nó.

dataNodeList = objNodeList[i].childNodes;

Em seguida, uso o método do item para aceder a ambos os nós que preciso para povoar a minha queda. O primeiro nó contém o campo CategoryID da base de dados, e o segundo nó contém o campo CategoriaName da base de dados. Crio um novo objeto Option, descon defini o texto para o Nome categoria, descoduto o valor para a categoriaID e adiciono-o ao drop-down drpCategoria. O código que é utilizado nas funções restantes utiliza o mesmo método para retirar os dados necessários da resposta XML e para povoar partes da página.Nota Desde que estamos a lidar com pequenas quantidades de dados aqui, usar o DOM é uma ótima maneira de retirar os dados que precisamos. Se estiver a lidar com uma grande quantidade de dados, poderá optar por utilizar o XSLT.

Como fazer com que tudo funcione

Agora que cobri os detalhes de como tudo isto funciona, é hora de ver como pode usar os ficheiros de amostras incluídos para vê-lo funcionar por si mesmo.

Implantação do serviço Web

Para implementar o serviço Web ASP.NET, basta desapertar a amostra de serviço Web anexada à raiz do seu servidor Web. Em seguida, terá de abrir o código para DynaProducts.asmx e alterar a cadeia de ligação. Pelo menos, terá de introduzir a palavra-passe SA. Depois de ter feito essa mudança, recomplete o serviço Web.

Implantação do ficheiro HTML

O ficheiro HTML contém uma variável chamada szUrl que contém um URL para o serviço Web. Encontrará esta variável na função getDataFromWS perto da parte inferior da função. Terá de alterar isso para o URL para o serviço Web que implementou acima.Depois de ter implantado o serviço Web e o ficheiro HTML, navegue para o ficheiro HTML. Quando estiver carregado, a categoria de down-down será povoada pelo primeiro pedido XMLHTTP ao serviço Web. Uma vez povoado, selecione uma categoria para dar início ao próximo pedido XMLHTTP que povoa o drop-down dos Produtos. A seleção de um produto a partir do drop-down dos Produtos irá preencher uma tabela com dados sobre esse produto.Note que a página não volta a ser publicada durante nenhum destes pedidos XMLHTTP. Esta é a beleza dos pedidos da XMLHTTP. Se eu tivesse feito isto numa página grande, a página também teria mantido a sua posição de deslocamento sem "piscar" para o utilizador. Na minha opinião, é uma coisa muito poderosa! Mais uma coisa: neste artigo, usei o XMLHTTP para consultar um serviço Web. Poderia facilmente tê-lo usado para fazer um pedido para uma página ASPX ou uma página ASP. As possibilidades de como usar esta tecnologia são infinitas. Espero que ache o XMLHTTP útil no seu futuro desenvolvimento de aplicações web.

Como sempre, sinta-se livre para submeter ideias sobre tópicos que deseja abordados em futuras colunas ou na Base de Conhecimento da Microsoft utilizando o formulário Ask For It.

Precisa de mais ajuda?

Quer mais opções?

Explore os benefícios da subscrição, navegue em cursos de formação, saiba como proteger o seu dispositivo e muito mais.

As comunidades ajudam-no a colocar e a responder perguntas, a dar feedback e a ouvir especialistas com conhecimentos abrangentes.