This page has been translated using an automatic translation service and the translation may not be very accurate.

ASP SOAP Client (English)

If you use this code and feel it is a useful tool, consider making a donation (through PayPal) to help support the project. You can donate as little or as much as you wish, any amount is greatly appreciated!

Italian page 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:

  1. 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

  2. using the parameters of initialization defined previously, it comes constructed demand SOAP (sXml) to send to the Web Service

  3. 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

  4. 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).