ASP SOAP Client (English)
For the original Italian page, please click on the link: http://www.guru4.net/articoli/asp-soap-client/default.aspx
To consume a Web Service using ASP is not one the simplest what, like, as an example, it is with with NET. Trying in net it is possible to find various implementazioni of client ASP but, nearly all, are limited to carry out a parsing of the answer, being dealt it like if it were a simple document XML, with all the limits that this simplification involves. In truth, with a little patience and little lines of script, it is possible to take advantage of the description of the service (WSDL, Web Service Description Language) in order independently to try in transparent way the answer to one called of a method of a Web Service, using directly the types of return (from their complexity) reproducing therefore that one that is the generation of the class proxy in NET (that is what ago Visual Study to added of a Web Reference or the tool of the SDK "wsdl.exe").
Interface and implemetazione of client the SOAP
Before analyzing to the code of client the SOAP, lend attention to following notes:
if you do not have much familiarità with the Web Service you can read to the article Introduction to the Web Service with NET, therefore from being able to totally comprise the rest of the article.
client the SOAP is realized using like language of scripting JScript for having the possibility to create to runtime given structures complex, constructed on answer SOAP, like defined from the WSDL of the service.
We analyze to the exposed interface and the relative implementazione of client the SOAP:
Initialization of the call
Client the SOAP will have to be inizializzato with the parameters of the service that we wish to interrogate, that is:
URL of the service, set up through the method setServiceUrl
Namespace of the service, set up through the method setServiceNamespace
Name of the method to recall, set up through the method setMethodName
Formulation of the specific parameters of interrogation for the method to recall, defined recalling the method addParameter that chip ax two arguments, the name of the parameter to set up and the correspondent value
We define our class and the methods of initialization of the service:
function SOAPClient()
{
var m_serviceurl;
var m_servicenamespace = "";
var m_methodname;
var m_parameters = new Array();
this.setServiceUrl = function(val)
{
m_serviceurl = val;
}
this.setServiceNamespace = function(val)
{
m_servicenamespace = val;
}
this.setMethodName = function(val)
{
m_methodname = val;
}
this.addParameter = function(pname, pval)
{
m_parameters[pname] = pval;
}
}
To carry out the call to the Web Service
After to have defined all the characteristics of the Web Service that we wish to interrogate, we pass to analyze the main method, call():
this.call = function()
{
// load WSDL
m_wsdl = Server.CreateObject("Microsoft.XMLDOM") ;
m_wsdl.load(m_serviceurl "?wsdl");
// build SOAP request
var sXml =
"<?xml version=\"1.0\" ?>"
"<soap:Envelope "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
"<soap:Body>"
"<" m_methodname " xmlns=\"" m_servicenamespace "\">";
for(var i in m_parameters)
sXml = "<" i ">" m_parameters[i] "</" i ">";
sXml = "</" m_methodname "></soap:Body></soap:Envelope>";
var xmlHTTP = Server.CreateObject("Msxml2.XMLHTTP");
xmlHTTP.Open("Post", m_serviceurl, false);
xmlHTTP.setRequestHeader("SOAPAction", m_servicenamespace "/" m_methodname);
xmlHTTP.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHTTP.Send(sXml);
// set raw xml
m_rawxml = xmlHTTP.responseXML.xml "";
// .NET way - the only way :-)
var nd = xmlHTTP.responseXML.selectSingleNode("//" m_methodname "Result");
if(nd == null)
{
if(xmlHTTP.responseXML.selectSingleNode("//faultcode/text()"))
throw new Error(500, xmlHTTP.responseXML.selectSingleNode("//faultcode/text()").nodeValue " - " xmlHTTP.responseXML.selectSingleNode("//faultstring/text()").nodeValue);
else
return null;
}
return this.soapresult2object(nd);
}
Analyzing the code over we can notice that:
it comes loaded in parser a XML (field private m_wsdl) the description of the service, recalling the URL of the Web Service with the added one of the parameter ?wsdl. Description document XML will come used in continuation in order to construct the correct types of return
using the parameters of initialization defined previously, it comes constructed demand SOAP (sXml) to send to the Web Service
through XMLHTTP demand SOAP comes sended to the Web Service in way sincrono; the answer comes therefore saved in the variable one m_rawxml, that it is also possible to expose like property of client the SOAP for being used directly to outside of the SOAPClient
the answer of the Web Service comes tried in order to construct the type of return (comprised an eventual error received from the serveur). You notice yourself that, also being SOAP a standard, in producing every truth has implemented in considerably various way the construction of the answer. The introduced code is in a position to trying the answers obtained from a service NET. In case it is wanted to be interrogated services exposed with different technology (Java, PHP, etc.) it will be necessary to estimate structure XML of the answer in specific way.
Construction of the result of the call
For the construction of the type of return it comes called in ricorsivo way the method node2object:
this.soapresult2object = function(node)
{
return this.node2object(node);
}
this.node2object = function(node)
{
// null node
if(node == null)
return null;
// text node
if(node.nodeType == 3 || node.nodeType == 4)
return this.extractValue(node);
// leaf node
if (node.hasChildNodes() && node.childNodes.length==1 && (node.firstChild.nodeType == 3 || node.firstChild.nodeType == 4))
return this.node2object(node.firstChild);
var isarray = false;
var el = m_wsdl.selectSingleNode("//s:element[@name='" node.nodeName "']");
isarray = (el!=null && el.attributes.getNamedItem("type")!=null && (el.attributes.getNamedItem("type").nodeValue "").toLowerCase().indexOf("arrayof") != -1);
// object node
if(!isarray)
{
var obj = null;
if(node.hasChildNodes())
obj = new Object();
for(var i = 0; i < node.childNodes.length; i )
{
var p = this.node2object(node.childNodes[i]);
obj[node.childNodes[i].nodeName] = p;
}
return obj;
}
// list node
else
{
// create node ref
var l = new Array();
for(var i = 0; i < node.childNodes.length; i )
{
var cn = node.childNodes[i];
l[l.length] = this.node2object(cn);
}
return l;
}
return null;
}
that inner it recalls extractValue in order to carry out the casting of the types primiti to you on the base of the WSDL:
this.extractValue = function(node)
{
var value = node.nodeValue;
var el = m_wsdl.selectSingleNode("//s:element[@name='" node.parentNode.nodeName "']");
var type = (el != null && el.attributes.getNamedItem("type") != null) ? (el.attributes.getNamedItem("type").nodeValue "").toLowerCase() : null;
switch(type)
{
default:
case "s:string":
{
return (value != null) ? value "" : "";
}
case "s:boolean":
{
return value "" == "true";
}
case "s:int":
case "s:long":
{
return (value != null) ? parseInt(value "", 10) : 0;
}
case "s:double":
{
return (value != null) ? parseFloat(value "") : 0;
}
case "s:datetime":
{
if(value == null)
return null;
else
{
value = value "";
value = value.substring(0, value.lastIndexOf("."));
value = value.replace(/T/gi," ");
value = value.replace(/-/gi,"/");
var d = new Date();
d.setTime(Date.parse(value));
return d;
}
}
}
}
Example of I use
It is supposed of having a Web Service for the
access to customer an external base that exposes a following method
with signature:
login(string username, string password): User
The method for the authentication will give back
therefore an object of type "User" (hypothetical characterized from
ID, Firstname, LastName, and SubscriptionDate) if the data of
authentications are valid or null in case the login it has outcome negative.
The example of following code ASP extension the interrogation of
the Web Service (URL and namespace is clearly fittizzi):
<% @Page Language="JScript" %>
<!--#include file="soapclient.asp"-->
<%
// recupero i dati di autenticazione dal form di login:
var username = Request.Form["username"];
var password = Request.Form["password"]
// preparazione della chiamata al Web Service:
var sc = new SOAPClient();
sc.setServiceUrl("http://www.altrosito.com/services/customer.asmx");
sc.setServiceNamespace("http://www.altrosito.com/services");
sc.setMethodName("Login");
sc.addParameter("username", username);
sc.addParameter("password", password);
// chiamata e verifica login:
var u = sc.call();
if(u != null) // login OK: visualizzazione del profilo utente
{
Response.Write("Benvenuto " u.Firstname " " u.Lastname "!<br />");
Response.Write("Il tuo identificativo è " u.ID.ToString() "<br />");
Response.Write("Sei iscritto dall'anno " u.SubscriptionDate.getFullYear());
}
else // login non valida
{
Response.Write("Dati non validi. Riprova.")
}
%>
Simple, not?
I use client-side
Client the SOAP is, but some modifications, usable
also client-side. The porting it has different complexity
according to how many and which browser we wish to support. As
far as Internet Explorer he is sufficient to sostuire the methods of
creation of members COM give "Server.CreateObject"to"new ActiveXObject". In a generalized manner we can think to use
bookcases Open Source and cross-borwser in order to obtain the members
XMLHTTP and XMLDOMDocument; they exist some various, more or
less or powerful complex and: enough a short search in Internet
in order to characterize that one that better adapted to our
requirements.
A limit that we must hold but present in the calls carried out
via Javascript to the inside of a client is that one of the
limitations taxes for emergency reasons: many browser do not
concur to carry out external remote calls to the dominion of the
running page.
In the article Javascript SOAP Client it comes supplieda complete implementazione of the bookcase in version client-side, compatible with the main ones browser and that it concurs to carry out calls it is in asynchronous modality sincrona that (AJAX).