Call a Web service from Javascript utilizing SOAP
without any extra libraries.
|
|
Environment: ASP .NET C#, and VB
What is all the buzz about AJAX? It's all about calling a web service from
your client web site without posting your web page to the host. Well AJAX
is more than that but in this example we'll consume a web service using a Javascript
client. What is AJAX? Well it's really a group of interrelated techniques
used to send and receive data asynchronously from the host, keeping your browser responsive while
gathering small amounts of data without refreshing the entire web page. You
call the web service using the
XMLHttpRequest object built into
your browser's DOM. Most newer browsers support the DOM object so the XMLHttpRequest object will be available. Calling a web service asynchronously from Javascript
can significantly reduce the round trip time required to get a small amount of data
from the host in using background processing.
If you are familiar with .NET web services you understand how efficient these calls
to the host are, no html web page, just the data you want returned in (often) XML
format. ASP .NET allows you to build powerful data driven applications...but all
that reposting to the host costs a lot of bandwidth. The XMLHttpRequest object
has been around since 2000 and is found on virtually any browser in use today. In this example we will call an ASP .NET web service
written in C# using a SOAP (Simple Object Access Protocol) envelope from a Javascript client.
Download the
Javascript code (.zip file) for this example.
The code that allows you to call a web service from javascript:
First the Javacript code to encapsulate the XMLHttpRequest object. This is a Javascript object with which we will create a new instance and and make the asynchronous call to the host.
function WebSvc() // Class Signature
{
// Encapsulates the elements of a XMLHttpRequest to an ASP .Net Web Service
WebSvc.prototype.CallWebService = function(url, soapXml, callback)
{
// Calls web service with XMLHttpRequest object. Utilizes a SOAP envelope for
// transport to and from Server. This is an asynchronous call.
// PARAM url - Fully qualified url to web service .asmx file
// PARAM sopXml - String containing SOAP envelope with request
// PARAM callback - Callback with signature callback(result,data) when call returns.
var xmlDoc = null;
if (window.XMLHttpRequest)
{
xmlDoc = new XMLHttpRequest(); //Newer browsers
}
else if (window.ActiveXObject) //IE 5, 6
{
xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlDoc)
{
//callback for readystate when it returns
var self = this;
xmlDoc.onreadystatechange = function() { self.StateChange(xmlDoc, callback); };
//set up the soap xml web service call
xmlDoc.open("POST", url, true);
xmlDoc.setRequestHeader("Content-Type", "text/xml");
xmlDoc.setRequestHeader("Content-Length", soapXml.length);
xmlDoc.send(soapXml);
}
else
{
if (callback)
{
callback(false, "unable to create XMLHttpRequest object");
}
}
};
WebSvc.prototype.StateChange = function(xmlDoc, callback)
{
// Callback supplied for XMLHttpRequest Object to monitor state and retrieve data.
// PARAM xmlDoc - XMLHttpRequest Object we're watching
// PARAM callback - Callback function for returning data, signature CallBack(result,data)
if (xmlDoc.readyState === 4)
{
var text = "";
if (xmlDoc.status === 200)
{
text = xmlDoc.responseText;
}
// Perform callback with data if callback function signature was provided,
if (callback !== null)
{
callback(xmlDoc.status === 200, text);
}
}
};
}
Next create a simple web service that we will be calling. In this case it's
a simple method that takes a string as input and returns an XML document with a
<date_time> element containing the string we passed as input and the date
and time. Obviously you would want to return a status element that allowed
you to determine whether the call was successful, but in this case there's not much
that can go wrong. An easy way to return an XML document from a web service
is to return an XmlNode which is easily obtained from the XmlDocument.DocumentElement;
This is the C# ASP .NET web service we will call with from our web page Javascript. The
method requires a string as input.
[WebMethod]
public XmlNode GetTime(string input)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<envelope><date_time>" + input + " " + DateTime.Now.ToLongDateString() +
DateTime.Now.ToLongTimeString() + "</date_time></envelope>");
return doc.DocumentElement;
}
When we call the web service
we will be using a SOAP envelope to communicate our request. This simple
javascript function creates the SOAP envelope and includes the input parameter
that the C# Web Service will be expecting.
This code is displayed here as an image but you can view the source of this page and copy the actual javascript function.
We supply a callback function so we can execute the request asyncronously from
our web page. This allows the web page to continue to be responsive while the
client to host request is made. When the call to the host completes the
callback function will display the result. If we don't want the callback
function we supply a null as a second parameter to the call. In the following
case a string parameter is passed into the web service.
In this example we are using the XMLHttpRequest.responseText value and will
receive the result in the form of plain text, and therefore will parse out the
<date_time> tag ourselves to get the result returned by the server. The
XMLHttpRequest object can also return an XML document but that is beyond the
scope of this article.
// This is the callback function that displays the result of the web service call
function callComplete(result, data)
{
if (result)
{
alert("SUCCESS " + getTagValue(data, "date_time"));
}
else
{
alert("Error occurred calling web service.");
}
}
// This function is called with a text input that is formatted with the server date and time
// when the web service call returns.
function getTime(message)
{
var soap = createSoapHeader(message);
//create the web service object and make the call
var webServiceCall = new WebSvc();
webServiceCall.CallWebService("services/WebService.asmx", soap, callComplete);
}
// Simple Javascript function that returns data contained within a set of tags.
function getTagValue(inputStr, tagName)
{
// Simple function to search for tagged element in a string,
// this function will not recurse and simply finds first ocurrence
// of tag in document.
// PARAM inputStr - string containing tagged document
// PARAM tagName - name of element to locate
// RETURNS string data between tagName element or "" if not found
var stag = "<" + tagName + ">";
var etag = "<" + "/" + tagName + ">";
var startPos = inputStr.indexOf(stag, 0);
if (startPos >= 0)
{
var endPos = inputStr.indexOf(etag, startPos);
if (endPos > startPos)
{
startPos = startPos + stag.length;
return inputStr.substring(startPos, endPos);
}
}
return "";
}
Call the web service from your web page as follows, supplying a parameter to
the web service.
onclick="getTime(getElementById('echoText').value)
To test the web service call, click the button. Download the
Javascript code (.zip file) for this example.
Important: If the address in the browser doesn't include www.hendricksongroup.com this call won't work, for instance if your browser address
bar shows http://hendricksongroup.com or any other URL the XMLHttpRequest object won't let you make cross site calls (more information below).
Using this technique will provide your site with increased responsiveness and dramatically
reduce the bandwidth requirements when only a portion of the web page data is required.
One important consideration is that the XMLHttpRequest object will not allow cross
site calls. For instance the call won't work if you landed on the site as http://yoursite.com
and the call is made to http://www.yoursite.com.