How To Call a .NET Web Service from Client Side JavaScript using Internet Explorer and MSXML

Article translations Article translations
Article ID: 555057 - View products that this article applies to.
Author: Chris Jackson MVP
Expand all | Collapse all

MORE INFORMATION

If you have a list of options that you want to offer based on user input on an HTML form, you can make this interactive by using the functionality that MSXML and JavaScript provide. For this article, we will illustrate creating a web service that feeds into a <SELECT> element so it is rendered as a list for the user to select from.
 
Creating a Stored Procedure to Get the Data You Need
 
The first step in creating your web service is to create a stored procedure that will fetch the data that you need based on the parameters the user has typed into the form. If your database provides XML functionality, it is often a good idea to leverage this functionality. In this example, I am using the FOR XML EXPLICIT to render XML that will function as the final HTML that the client will render. If your database platform does not support this feature, this manipulation can either be done on the server using the classes in System.Xml or on the client using MSXML.
 
CREATE PROCEDURE dbo.WebServiceProc (@param VARCHAR(4)) AS

  SELECT  1 AS Tag,

          NULL AS Parent,

          NULL AS [SELECT!1],

          '10' AS [SELECT!1!SIZE],

         'selectList' AS [SELECT!1!ID],

         'font-family:Verdana;font-size:XX-Small;width:100%;' AS [SELECT!1!STYLE],

         NULL AS [OPTION!2]

  UNION ALL

  SELECT  2 AS Tag,

          1 AS Parent,

          NULL AS [SELECT!1],

          NULL AS [SELECT!1!SIZE],

          NULL AS [SELECT!1!ID],

          NULL AS [SELECT!1!STYLE],

          MyDatabase.dbo.MyTable.MyListItem AS [OPTION!2]

  FROM    MyDatabase.dbo.MyTable

  WHERE   MyDatabase.dbo.MyTable.MyParameter = @param

  ORDER BY [OPTION!2]

  FOR XML EXPLICIT

 
This stored procedure, using SQL Server 2000, will output something like this:
 
<SELECT SIZE="10" ID="mySelectObject" STYLE="font-family:Verdana;font-size:XX-Small;width:100%"><OPTION>Option 1</OPTION><OPTION>Option 2</OPTION></SELECT>

 
As you can see, this XML can be used directly on the client, as it is valid HTML.
 
Creating the Web Service
 
The next step is to create the web service that you intend to consume. If you are using SQL Server 2000, most of the work is already done for you. If not, then you may need to work with the data that your database returned in order to form it into XML that you can pass back to the client. First, you should create a new web service in your project. Then, the following C# code will return the XML that you need on the client in order to render this SELECT object:
 
[WebMethod]

public XmlDocument GetSelectObject(string param) {

  XmlDocument xmlReturnDocument = new XmlDocument();

  using (SqlConnection connMyConnection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"])) {

    using (SqlCommand cmdWebServiceProc= new SqlCommand("MyDatabase.dbo.WebServiceProc", connMyConnection)) {

      cmdWebServiceProc.CommandType = CommandType.StoredProcedure;

      cmdWebServiceProc.Parameters.Add("@pram", SqlDbType.VarChar, 4).Value = param;

      try {

        connMyConnection.Open();

        XmlTextReader xtrSelectXml= (XmlTextReader)cmdWebServiceProc.ExecuteXmlReader();

        xmlReturnDocument.Load(xtrSelectXml);

      } catch (SqlException ex) {

        // error handling elided for clarity

      }

    }

  }

  return xmlReturnDocument;

}

 
Now you have created a web service, which you should be able to test using the browser interface that the .NET framework provides for you.
 
Creating the Client Side Script
 
Now that we have a web service to call, we can implement the client side script. First of all, in the HTML code, you can create a div into which we will insert the SELECT element that we are creating:
 
<div id="divWebServiceResults" />

 
When I am creating a client side script to make a web service call, I like to provide the user with feedback so they will understand why their browser is not responding for a moment or two, and that some action is being taken. However, Internet Explorer does not re-render the page it is displaying until such time as the function returns, so we are going to have to break our call up, creating a function that displays the user input first, and then scheduling a call to actually process the web service call:
 
function getWebServiceResults() {

  var divFeatures = document.getElementById("divWebServiceResults");

  divFeatures.innerHTML = "<SELECT size='10' id='selectList' style='font-family:Verdana;font-size:XX-Small;width:100%;'>" +

                          "<OPTION>Please wait while I load data...</OPTION>" +

                          "</SELECT>";

  window.setTimeout(getWebServiceResultsAfterInit, 1);

}

 
The actual processing occurs on callback, which we delay by 1 millisecond. Here, we are going to create an XML Document and an XML HTTP object. We are going to use XML HTTP to post to the web service, and store the results in this document. When we create these objects, we are going to iterate through an array of program IDs. For a number of reasons, Microsoft has decided to stop using version independent program IDs. We want to make sure that we are using the most current version, so we are going to start at the latest - 4.0. We will then iterate backwards until we reach version 1.0. This ensures that most clients will work with this script, as MSXML has been included with the operating system since Windows 95 OSR 2.5. If your clients are using Windows 2000, they will have version 2.5 of MSXML by default. If they are using Windows XP, then they will have MSXML 3.0 installed. Once we have instantiated this object, we can fetch the value for the parameter from the current form, build our SOAP envelope (which is simply an XML string - if you want to review the specific format for your web service, the ASMX browser interface will provide this for you when you browse to a method), set our request headers (which can also be reviewed in the browser interface) and submit the request. We set up our call to call yet another function when the HTTP request is complete, as this call will happen asynchronously.
What you should notice here is the simplicity of making a web service request. All that you need to do is review the calling convention, and build up an HTTP request (which is nothing but plain text) that conforms to this convention. By setting the headers and building some XML to send the SOAP request, you have done all that you need to do.
 
var objXmlDoc;

var objHttp;

function getWebServiceResultsAfterInit() {

  // Must be using IE for this to work

  if (window.ActiveXObject) {

    // Create the XML Document object

    var bDocument = false;

    var aszDocumentProgIDs = [ "MSXML2.DOMDocument.4.0",

                               "MSXML2.DOMDocument.3.0",

                               "MSXML2.DOMDocument",

                               "MSXML.DOMDocument",

                               "Microsoft.XmlDom" ];

    for (var i=0; !bDocument && i < aszDocumentProgIDs.length; i++) {

      try {

        objXmlDoc = new ActiveXObject(aszDocumentProgIDs[i]);

        bDocument = true;

      } catch (objException) {

        // error handling elided for clarity

      }

    }

    // Create the XML HTTP object

    var bHttp = false;

    var aszHttpProgIDs = [ "MSXML2.XMLHTTP.4.0",

                           "MSXML2.XMLHTTP.3.0",

                           "MSXML2.XMLHTTP",

                           "Microsoft.XMLHTTP" ];

    for (var i = 0; !bHttp && i < aszHttpProgIDs.length; i++) {

      try {

        objHttp = new ActiveXObject(aszHttpProgIDs[i]);

        bHttp = true;

      } catch (objException) {

        // error handling elided for clarity

      }

    }

    // If we failed to create both objects, then throw an exception and return

    if (!bDocument || !bHttp) {

      throw "MSXML not found on your computer.";

      return;

    }

    // Get the parameter

    var oParameter = document.getElementById("textboxParameter");

    var szParameter = oParameter.value;

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

                  "    <GetSelectObject xmlns=\"http://example.org/webservices/\">" +

                  "      <param>" + szParameter + "</param>" +

                  "    </GetSelectObject>" +

                  "  </soap:Body>" +

                  "</soap:Envelope>"

    // Set up the post

    objHttp.onreadystatechange = getWebServiceResultsAfterLoad

    objHttp.open("post", "/MyWebService.asmx");

    objHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");

    objHttp.setRequestHeader("SOAPAction", "http://example.org/webservices/GetSelectObject");

    objHttp.send(strEnvelope);

  }

}

 
Now that we have sent our request, we simply need to wait for the request to return as completed, and implement our handler to get the results and output the results. We check the ready state to ensure that it is completed. If so, then we can find our object, and insert our text. Here, we can take advantage of the fact that we formatted our XML return set as valid HTML, and we can simply find the SELECT tag (which is the root of what we requested) and set the innerHTML of our div to that return. In our implementation here, we have SQL Server doing all of the work to get the results and format them properly, so the rest of our code needs only to forward along these results until it finally reaches the browser. You should note also that we do search for a specific node. Because we are working with raw XML, our results are going to be embedded inside of an XML SOAP envelope, and we want to dig into this to get at only the results that we expect to find.
 
function getWebServiceResultsAfterLoad() {

  if (objHttp.readyState == 4) {

    // Get the return envelope

    var szResponse = objHttp.responseText;

    objXmlDoc.loadXML(szResponse);

    // Get the div object to insert into

    var divWebServiceResults = document.getElementById("divWebServiceResults");

    // Select the 'Select' node and put its XML into the inner HTML

    var nodeSelect = objXmlDoc.getElementsByTagName("SELECT").item(0);

    if (nodeSelect.childNodes.length > 0) {

      divWebServiceResults.innerHTML = nodeSelect.xml;

    } else {

      divWebServiceResults.innerHTML = "<SELECT size='10' id='selectList' style='font-family:Verdana;font-size:XX-Small;width:100%;'>" +

                                       "<OPTION>No data found for this parameter</OPTION>" +

                                       "</SELECT>";

    }

  }

}

 
Using this technique, you can solve a number of issues. For example, you might want to dynamically list the products you sell based on the state that a customer is located in. You may want to create a DHTML tree control, but you don't want to load all of the nodes at one time because the tree is too big, so you can use a web service call to get only the children of one branch at a time, speeding your rendering. Using web services on the server allows you to implement such dynamic behavior in a way that the .NET Framework explicitly supports, and should make the development task much simpler.

Properties

Article ID: 555057 - Last Review: February 13, 2004 - Revision: 1.0
APPLIES TO
  • Microsoft .NET Framework 1.1
  • Microsoft Peer Web Services 3.0
  • Microsoft .NET Framework 1.0 Service Pack 3
Keywords: 
kbpubtypecca kbpubmvp kbhowto KB555057
COMMUNITY SOLUTIONS CONTENT DISCLAIMER
MICROSOFT CORPORATION AND/OR ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY, RELIABILITY, OR ACCURACY OF THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN. ALL SUCH INFORMATION AND RELATED GRAPHICS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT AND/OR ITS RESPECTIVE SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THIS INFORMATION AND RELATED GRAPHICS, INCLUDING ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, TITLE AND NON-INFRINGEMENT. YOU SPECIFICALLY AGREE THAT IN NO EVENT SHALL MICROSOFT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, INCIDENTAL, SPECIAL, CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, ARISING OUT OF OR IN ANY WAY CONNECTED WITH THE USE OF OR INABILITY TO USE THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF MICROSOFT OR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES.

Give Feedback

 

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