Monday, July 14, 2008

Calling Webservices from VB Script and Java Script client code - A step by step introduction

We often need ability to call a web service from client scripts itself. In todays Service Oriented Architecture this has become more essential than anything. Recently I faced a requirement of calling web service from VB Script, after some google-ing, I found there is no consolidated easy step by step article any one has written before. Though I did get many code snippets but eventually had to figure out how to make them work with my application and also how the code works.
Thus this articles mainly addresses this issue, I have tried to cover some of the the commonly possible scenarios of a web service call from client script and also considered most of the possible technologies which are available for Microsoft .Net Framework at present.
At the outset I should mention that I have tested my code only for Microsoft .Net Framework web services, this scripts won't work directly without modification with web services of Java and other technologies. The header and SOAP format and other details differ, and thus should be accordingly be modified into the scripts to make them work.
Also this is article is actually only a quick start, a single place to tell you how to do the basics and what are the available options. It is not intended to be extensive by any means and only personal work.
Further: JS and VBS files available here is freely distributable, and I do not endorse anything I said here for commercial purposes but only for learning purposes.

Introduction:

A script which runs under the browser is often limited to what is already rendered into the browser and can typically only manipulate those objects. Script do not have direct access to the server side code/objects. Often when something needs to be updated into page a re-load is necessary to re-render and update the control with new information. But this approach is costly and leads to an unnecessary round trip. Asynchronous calls to the server object comes to rescue here. The technology AJAX is wholly based on this requirement. You might have notices how gmail achieves such gigantic work without reloading the whole page even once. All this is archived thanks to the ability of making Asynchronous calls. Microsoft has a inbuilt trusted component called XMLHTTP which will give this ability to make asynchronous calls to client side script. Thus in a way XMLHTTP object is at the heart of AJAX technology. XMLHTTP object can be similarly be used to make remote calls to the web service. Web service is an endpoint which provides some service to be called by other remote code, typically they are web methods. Web service follows its own protocol called SOAP which stands above the HTTP protocol layer. What typically happens is that an HTTP request GET or POST is formed out of the thing called SOAP envelope. That is the SOAP envelope is the body part of the HTTP request and thus is important in making a asynchronous call to web service from client side. Although web service may also be called only through simple HTTP but only if the server supports it.

Through XMLHTTP object and SOAP protocol.

Let us first assume existence of a Web Service in local machine having URI http://localhost/MyWebService/Service.asmx having a Web method having MyWebMethod which takes one parameter named sParameter and returns a single string. The web service is written in C# using Visual Studio 2005.



VB Script

' WebService URL
Const serviceUrl = "http://localhost/MyWebService/Service.asmx"

Const sParameter = "3B759400006202020546" 'String parameter

Dim nodes
Dim oXml

Dim xmlDoc

Dim strXmlData

' Create HTTP Object, this will make HTTP calls.
Set oXml = CreateObject("MSXML2.XMLHTTP")

' We need to parse the returned data from WebService, which is in XML form.
Set xmlDoc = CreateObject("Microsoft.XMLDOM")

' Make SOAP Header and envlope here. In .Net WebService, if you call the
' WebService from local machine, it will show the SOAP Header and Envlope
' and Body which will be necessary to call a particular WebMethod in the
' help/description section of ASMX file. This can used excatly without an
' further modification to call a WebMethod, avoiding the need of
' understanding the SOAP details seperately. I have used the same
' information below.


' Use double qoutes to escape the qoutes in a string.
strXmlData = "<?xml version=""1.0"" encoding=""utf-8""?>"

strXmlData = strXmlData & "
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" >"

strXmlData = strXmlData & "
<soap:Body>"
' Note this whole XML wrapped is what .Net uses to call the WebService
' and calls it SOAP, MyWebMethod is actual WebMethod name.

strXmlData = strXmlData & " <MyWebMethod
xmlns=""http://www.tempuri.com/"" >"

' The below parameter is only a string, if more complex parameter needs to ' be passed, the
' WebService description of the Method it self will show
what is the XML needed to serialize the
' complex Parameter.


strXmlData = strXmlData & " <sParameter>" & sParameter & "</sParameter>"

strXmlData = strXmlData & " </MyWebMethod>"

strXmlData = strXmlData & " </soap:Body>"

strXmlData = strXmlData & "</soap:Envelope>"

oXml.open "POST", strUrl, False

oXml.setRequestHeader "Content-Type", "text/xml"

oXml.send strXmlData

' Check whether HTTP OK. You can check other conditions if you want and
' handle error such as 404.

If oXml.Status = "200" Then

If xmlDoc.loadXML(oXml.responseText) Then

' The response of the call to the WebMethod will be enclosed in an tag of
' the form WebMethodName + Response, that is concatation of the string
' 'MyWebMethod' and 'Response', yielding to 'MyWebMethodResponse'

nodes = xmlDoc.documentElement.selectSingleNode("//MyWebMethodResponse").attributes(0).text

' You may write other complex parsing logic using XMLDOM here to parse more ' complex returned object into object form. Your WebMethod may itself do
' its custom serialization, which you need to de-serialize it here, and
' assign it to a equivalent object in VB Script and use it.

MsgBox nodes

End If

Else

MsgBox "Error: " & oXml.Status & " - " & oXml.statusText

End If

Java Script

var strUrl = "http://localhost/MyService/Service.asmx";
var sATR = "3B759400006202020546";

var oXml;

var xmlDoc;

var strXmlData;


oXml = new ActiveXObject("MSXML2.XMLHTTP"); // Create HTTP ActiveX object instance

xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); // Create XMLDom ActiveX object instance

strXmlData = ""; // Notice escape sequence for quotes

// Make soap envlope, follow Listing 1 for detail discription.

strXmlData = strXmlData + "<?xml version=""1.0"" encoding=""utf-8""?>";

strXmlData = strXmlData + "<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" >";

strXmlData = strXmlData + " <soap:Body>";

strXmlData = strXmlData + " <MyWebMethod
xmlns=""http://www.tempuri.com/"" >";

strXmlData = strXmlData + " <sParameter>" & sParameter & "</sParameter>"

strXmlData = strXmlData + " </MyWebMethod>";

strXmlData = strXmlData + " </soap:Body>";

strXmlData = strXmlData + "</soap:Envelope>"
;

oXml.open( "POST", strUrl, false);

oXml.setRequestHeader("Content-Type", "text/xml");

oXml.send(strXmlData);

if(oXml.Status == "200")
{

if (xmlDoc.loadXML(oXml.responseText))
{

var nodes;
nodes = xmlDoc.documentElement.selectSingleNode("//GetCardMapResponse").attributes(0).text;


alert( nodes);

}
}
else
{
alert( "Error: " + oXml.Status);
}




Through XMLHTTP object and HTTP protocol only.
VB Script

Java Script

By Using WebService.htc behaviour for Javascript

Microsoft Web Services Enhancements (WSE)

No comments: