ASP.NET Support Voice-kolumn

Dynamiska siduppdateringar med XMLHTTP

För att anpassa den här kolumnen efter dina behov vill vi bjuda in dig att skicka in idéer om ämnen som intresserar dig och problem som du vill ta upp i framtida Knowledge Base-artiklar och supportröstkolumner. Du kan skicka dina idéer och feedback med hjälp av formuläret Fråga efter den. Det finns också en länk till formuläret längst ned i den här kolumnen.

Introduktion

Ett av mina favorit sätt att studera användbarheten för webbprogram är att se min fru navigera runt på en webbplats. Hon kan komma runt på Internet ganska bra, men hon vet lite om de tekniska aspekterna på låg nivå (det hon kallar "de lådiga grejerna") som får det att fungera. På en kväll nyligen tittar jag på när min fru ser ett program för e-handel från en av de stora pojkarna. Hon gjorde en för många fallande inmatningar i en produktlista, och åt var och en av de delar av urvalet som gjorts tidigare. När hon klickade på ett objekt i varje listrutan publicerade sidan tillbaka för att hämta data för nästa listrutan. Det var frustrerande för henne eftersom hennes intryck var att det tog lång tid på grund av inläggsbacken. Frustrationsnivån som hon hade hade kunde lätt dämpas av utvecklarna av programmet om de bara använde XMLHTTP för att hämta data i stället för att publicera tillbaka. Det är vad den här månadens kolumn handlar om. Jag ska visa hur du använder XMLHTTP för att uppdatera en del av en webbsida med data från en Microsoft ASP.NET-webbtjänst utan att göra ett inlägg. Det här kommer att vara riktigt coolt! Lita på mig.

Översikt

XMLHTTP fungerar genom att skicka en begäran till webbservern från klienten och returnera en XML-data ö. Beroende på strukturen hos den XML som tas emot kan du använda XSLT eller XML DOM för att ändra den och binda delar av sidan till dessa data. Det här är en mycket kraftfull teknik. NoteMicrosoft erbjuder ett webbtjänstbeteende för Internet Explorer som gör asynkrona samtal ASP.NET webbtjänster snabbt och enkelt. Det här beteendet stöds dock inte och är inte det bästa sättet att uppdatera en sida asynkront. Du bör använda XMLHTTP i stället! I exemplet ska jag gå igenom i den här kolumnen ska jag ringa tre webbtjänstsamtal till en ASP.NET webbtjänst via XMLHTTP. Webbtjänsten skickar en fråga till Northwind-databasen på den lokala SQL Server-servern och returnerar en datamängd till klienten i form av ett XML-diffgram. Sedan använder jag XML DOM för att tolka XML-data och dynamiskt uppdatera delar av sidan. Allt detta görs utan ett inlägg.

Webbtjänsten

Webbtjänsten jag använder heter DynaProducts. Det är en ASP.NET webbtjänst som är skriven i C# och som innehåller följande tre metoder.

  • GetCategories – Returnerar en datamängd som innehåller alla kategorier i tabellen Kategorier.

  • GetProducts – Returnerar en datamängd som innehåller alla produkter i kategorin som skickas till metoden.

  • GetProductDetails – Returnerar en datamängd som innehåller information om produkten vars Produkt-ID skickas till metoden.

HTML-sidan

Det första som kan få dig att tänka på det här exemplet är att den sida som jag uppdaterar, men ASP.NET webbtjänsten, inte är en ASP.NET sidan. Det är bara en vanlig HTML-sida. Men jag har lagt till en hel del JavaScript på klientsidan på sidan och det är skriptet som ringer upp webbtjänsten.Vi tittar på det första kodavsnittet från HTML-sidan.

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);  }}

Det här är det största kodstycket på sidan och jag vill gå igenom det i detalj så att du förstår vad som händer.Högst upp i det här skriptblocket skapade jag två variabler: objHttp och objXmlDoc. Det här är de variabler som jag använder för mitt XMLHTTP-objekt och mitt XML DOM-objekt. Omedelbart efter det är funktionsdefinitionen för funktionen getDataFromWS. Det här är den funktion som ansvarar för att göra klientanropet till webbtjänsten. Den har följande fyra argument, av vilka två är valfria:

  • methodName – Namnet på den metod du vill anropa i webbtjänsten.

  • dataSetName – Namnet på den datamängd som returneras av webbtjänsten.

  • wsParamValue – Värdet på parametern som skickas till webbtjänsten om tillämpligt. (Valfritt)

  • wsParamName – Namnet på parametern som skickas till webbtjänsten om tillämpligt. (Valfritt)

Låt oss dela upp funktionen GetDataFromWS i delar och diskutera var och en. Här är det första avsnittet:

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

Det här kodblocket skapar XMLHTTP-objektet och XML-dokumentobjektet. I nästa steg börjar jag skapa SOAP-kuvertet.

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

I den här koden tilldelar jag SOAP-kuvertet till en strängvariabel så att jag kan överföra den till webbtjänsten. Det är faktiskt ganska enkelt att ta reda på hur du formaterar SOAP-kuvertet för webbtjänsten. Bläddra till webbtjänsten och klicka på någon av metoderna för att visa ett SOAP-kuvert för den metoden. Det här är till exempel vad som visas när jag bläddrar till Metoden GetCategories för wsXMLHTTP-webbtjänsten som jag skapade för den här artikeln:alternativtextASP.NET beskriver hur SOAP-kuvertet ska formateras för ett HTTP-INLÄGG och en HTTP GET. I det här exemplet kommer jag att använda HTTP POST. Så långt är allt bra. Nu ska vi titta på nästa avsnitt med kod.

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

När en begäran görs via XMLHTTP använder XMLHTTP-objektet en readyState-egenskap för att spåra status för begäran. När alla data har tagits emot från webbtjänsten ändras readyState-egenskapen till värdet 4. Med egenskapen onreadystatechange för XMLHTTP-objektet kan du konfigurera en anroparfunktion som anropas när readyState-egenskapen ändras. Genom att se till att data har tagits emot i sin helhet kan jag fortsätta att agera på dessa data tills jag är redo.När alla data har tagits emot skapar jag en XML-data ö med svaret med hjälp av egenskapen responseText. Som du förmodligen vet är svaret från en webbtjänst i XML-format. I det här fallet returnerar jag en Microsoft ADO.NET datamängd. I nästa avsnitt i det här kodblocket används en växlingssats för att anropa lämplig funktion baserat på namnet på den datamängd som returneras från webbtjänsten. Jag går in på koden för funktionerna lite i detalj senare.Nu ska vi titta på den kod som faktiskt utför XMLHTTP-begäran.

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);

Variabeln szUrl innehåller den URL som används för att anropa webbtjänsten för att göra den tydligare. Sedan har jag ett OM-uttryck som söker efter parametrar som överförs som ett QueryString-värde. I din miljö kanske du vill lägga till parametrar i SOAP-kuvertet. Oavsett hur du gör det fungerar det utmärkt.Den öppna metoden för XMLHTTP-objektet kallas nästa. Jag har använt de tre första argumenten för metoden öppna; metoden, URL:en och ett booleskt värde som anger om samtalet är asynkront eller inte. Viktigt om du ringer ett asynkront samtal eftersom jag är här måste du konfigurera en funktion för callback via egenskapen onreadystatechanged. När rubriken för begäran för innehållstypen har angetts skickar jag begäran som ett SOAP-kuvert med strängvariabeln I som ifylld tidigare. Nu har vi gått över all kod som gör XMLHTTP-begäran. Nu ska vi titta på koden som hanterar gränssnittet i webbläsaren och som hanterar svaret från webbtjänstsamtalet.Först tittar vi på funktionen som anropas när sidan först läses in.

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

Det första jag gör i den här funktionen är att skapa en variabel för att lagra funktionssignaturen för getDataFromWS. Det gör jag eftersom jag går till anropa window.setTimeout i slutet av den här funktionen för att anropa funktionen getDataFromWS. Syftet med den här metoden är att låta mig visa status för användaren medan jag väntar på att webbtjänstsamtalet ska slutföras. Observera att jag ändrar innertexten i en DIV för att visa ett meddelande som anger att data hämtas. Sedan schemalägger jag funktionen getDataFromWS via anropet window.setTimeout, och jag anger att den ska köras i en millisekund.

Bearbeta svaret på webbtjänsten

Kom ihåg tidigare att jag använde egenskapen onreadystatechanged för att konfigurera en funktion för callback. Kom också ihåg att anropa-funktionen innehåller en switch-sats som anropar en viss funktion baserat på namnet DataSet. I det här fallet är datauppsättningsnamnet CategoriesDS. Därför anropas funktionen processkategori från funktionen anropas från anroparfunktionen. Nu ska vi titta på den funktionen för att se hur du använder XML DOM för att tolka svaret från webbtjänsten.

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

Kom ihåg att funktionen getDataFromWS laddade XML från svaret i objXmlDoc-objektet. I funktionen processKategori tar jag XML-koden och tolkar igenom den för att fylla i listrutan Kategori.Det första jag gör är att skapa ett IXMLDOMNodeList-objekt med en del av XML-svaret. Den datamängd som jag återvänder från webbtjänstsamtalet returneras som ett diffgram, och den enda delen av det svaret som jag verkligen är intresserad av är data från datatabellen som jag har infogat i datamängden. Jag kan komma åt det genom att skapa ett IXMLDOMNodeList-objekt från XML-blocket som innehåller DataTable.Om du tittar på koden för webbtjänsten ser du att jag skapar en datatabell som heter Kategorier och lägger till den i datamängden. När XML returneras från webbtjänsten finns datamängden i ett <CategoriesDS>-block och varje rad från DataTable finns i separata <Categories>-block som visas i XML-filen nedan.Följande filer kan laddas ned från Microsoft Download Center: Ladda ned ladda ned GetCategories.xml paketet nu. Ladda ned Ladda ned WSXMLHTTP.exe paketet nu.Om du vill ha mer information om hur du laddar ned Microsoft Support-filer klickar du på följande artikelnummer för att visa artikeln i Microsoft Knowledge Base:

119591 Så här hämtar du Microsoft-supportfiler från onlinetjänster som Microsoft skannade filen efter virus. Microsoft använde det senaste virusidentifieringsprogrammet som var tillgängligt det datum då filen publicerades. Filen lagras på servrar med säkerhet som hjälper till att förhindra obehöriga ändringar i filen.För att få det XML-block som innehåller den datatabellen använder jag följande kod:

objNodeList = objXmlDoc.getElementsByTagName("Categories");

Detta returnerar ett IXMLDOMNodeList-objekt som innehåller <kategorier> nod. Sedan upprepar jag den listan med en för 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";    }

Jag vet redan att varje <->-nod kommer att ha två noder som jag behöver: <-ID>-nod och <kategorinamn> nod. Därför är det första jag gör att skapa en ny IXMLDOMNodeList och fylla den med underordnade noder för den aktuella <kategorier> nod.

dataNodeList = objNodeList[i].childNodes;

Sedan använder jag objektmetoden för att komma åt båda noderna som jag behöver fylla i listrutan. Den första noden innehåller fältet Kategori-ID från databasen och den andra noden innehåller fältet Kategorinamn från databasen. Jag skapar ett nytt Alternativ-objekt, anger texten till Kategorinamn, anger värdet till Kategori-ID och lägger till det i listrutan drpCategory. Koden som används i de återstående funktionerna använder samma metod för att hämta de data som behövs från XML-svaret och för att fylla i delar av sidan.Observera att vi hanterar små mängder data här, att använda DOM är ett bra sätt att ta fram de data vi behöver. Om du hanterade en stor mängd data kan du välja att använda XSLT i stället.

Så här får du allt att fungera

Nu när jag har gått igenom detaljerna om hur allt det här fungerar är det dags att gå igenom hur du kan använda de inkluderade exempelfilerna för att se hur det fungerar för dig själv.

Distribuera webbtjänsten

Om du vill ASP.NET webbtjänsten zippa upp det bifogade webbtjänstexempelet till roten på webbservern. Du måste sedan öppna koden för DynaProducts.asmx och ändra anslutningssträngen. Du måste åtminstone ange SA-lösenordet. När du har gjort den ändringen kompilerar du om webbtjänsten.

Distribuera HTML-filen

HTML-filen innehåller variabeln szUrl som innehåller en URL-adress till webbtjänsten. Du hittar den här variabeln i funktionen getDataFromWS nästan längst ned i funktionen. Du måste ändra det till URL-adressen för webbtjänsten som du distribuerade ovan.När du har distribuerat både webbtjänsten och HTML-filen bläddrar du till HTML-filen. När den läses in fylls listrutan Kategori i av den första XMLHTTP-begäran till webbtjänsten. När den har fyllts i väljer du en kategori för att starta nästa XMLHTTP-begäran som fyller i listrutan Produkter. Om du väljer en produkt från listrutan Produkter fylls en tabell i med data om produkten.Observera att sidan inte publicerar igen under någon av dessa XMLHTTP-begäranden. Det är det som är det vackra med XMLHTTP-begäranden. Om jag hade gjort detta på en stor sida hade sidan också behållit sin rullningsposition utan att "blinka" för användaren. Om du frågar mig är det här ganska kraftfulla saker! En sak till: i den här artikeln använde jag XMLHTTP för att fråga en webbtjänst. Jag kunde ha lika enkelt använt den för att begära en ASPX-sida eller en ASP-sida. Möjligheterna för hur du kan använda den här tekniken är oändliga. Jag hoppas att du tycker att XMLHTTP kan vara användbart i din framtida utveckling av webbprogram.

Som alltid kan du skicka idéer om ämnen som du vill ta itu med i framtida kolumner eller i Microsoft Knowledge Base med hjälp av formuläret Fråga efter it.

Behöver du mer hjälp?

Vill du ha fler alternativ?

Utforska prenumerationsförmåner, bläddra bland utbildningskurser, lär dig hur du skyddar din enhet med mera.

Communities hjälper dig att ställa och svara på frågor, ge feedback och få råd från experter med rika kunskaper.