Roger Wolter
Microsoft Corporation
May 2001
Summary: This article covers the basics of using the SOAP Client software included with Microsoft Windows XP Professional to access Web Services using SOAP. It begins with a brief introduction to SOAP and WSDL standards and then discusses how to implement a client that can communicate with a SOAP-enabled Web service. (16 printed pages)
Contents
Introduction
What Is SOAP?
What Is WSDL?
Building A Simple Client Application
Next Steps
The SOAPClient Object
Mssoapinit Method
ClientProperty Property
ConnectorProperty Property
Detail Property
HeaderHandler (SOAPClient)
Faultactor Property (SOAPClient)
Faultcode Property (SOAPClient)
Faultstring Property (SOAPClient)
Microsoft® Windows® XP Professional includes the client portion of the Microsoft SOAP Toolkit 2.0, making it possible to build SOAP client applications or to distribute them to Windows XP Professional clients without distributing the client portions of the SOAP Toolkit 2.0. This paper covers the basics of using the SOAP client software included with Windows XP to access Web services using SOAP. It begins with a brief introduction to SOAP and Web Services Description Language (WSDL) standards, and then discusses how to implement a client that can communicate with a SOAP-enabled Web service.
SOAP, which stands for Simple Object Access Protocol, is defined by the SOAP standard available at http://www.w3.org/TR/SOAP. The SOAP protocol defines the format of standard XML messages that are used to communicate among systems. Because the message format is standardized and based on the XML standard, SOAP can be used to communicate among multiple computer architectures, languages, and operating systems. SOAP enables a new class of applications called Web services, which expose services in a standard way so that application developers can create new applications by putting together services from many different sources on the Web.
There are four main areas covered by the SOAP specification: a required SOAP Envelope format that defines what the envelope that surrounds the XML content of a SOAP message must look like; an optional set of encoding rules that defines how language types are mapped to XML in a SOAP message (since this is defined in section 5 of the specification, it is referred to as "section 5 encoding"); an optional RPC format that defines how function calls are expressed in SOAP messages; and an HTTP binding that defines how SOAP messages may be exchanged through HTTP. HTTP is the only communications protocol binding defined by the standard; thus almost all SOAP implementations include an HTTP binding. Note that SOAP doesn't impose limitations on what other communications protocols can be used to transport SOAP messages.
Here's a simple SOAP message:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <SOAPSDK1:Add xmlns:SOAPSDK1="http://tempuri.org/message/"> <a>333</a> <b>888</b> </SOAPSDK1:Add> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Let's go through this in detail to understand the format of a SOAP message. The first line is the XML declaration that defines the character set used in the SOAP document. The Envelope element is a required element that is always the root of a SOAP message, and is always in the "http://schemas.xmlsoap.org/soap/envelope/" namespace.
The SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" attribute defines the encoding style used in the message. In this case, standard section 5 encoding is used. The Body sub element of the Envelope element contains the SOAP Message. As defined in section 7 of the SOAP specification, the Add element represents a call on an operation named Add. The sub elements of Add are the parameters of the Add method call.
The response to this message would look like this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <SOAPSDK1:AddResponse xmlns:SOAPSDK1="http://tempuri.org/message/"> <Result>1221</Result> </SOAPSDK1:AddResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
WSDL stands for Web Service Description Language. In order to successfully call a Web service you will need to know how to get to the service, what operations the service supports, what parameters the service expects, and what the service returns. WSDL provides all of this information in an XML document that can be read or machine-processed.
To understand the format of a WSDL file, let's examine the following WSDL file:
<?xml version="1.0" encoding="UTF-8" ?> <definitions name="net.xmethods.services.currencyexchange.CurrencyExchange" targetNamespace="http://www.themindelectric.com/wsdl/ net.xmethods.services.currencyexchange.CurrencyExchange/" xmlns:tns="http://www.themindelectric.com/wsdl/ net.xmethods.services.currencyexchange.CurrencyExchange/" xmlns:electric="http://www.themindelectric.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="getRateRequest1"> <part name="country1" type="xsd:string" /> <part name="country2" type="xsd:string" /> </message> <message name="getRateResponse1"> <part name="Result" type="xsd:float" /> </message> <portType name="net.xmethods.services. currencyexchange.CurrencyExchangePortType"> <operation name="getRate" parameterOrder="country1 country2"> <input message="tns:getRateRequest1" /> <output message="tns:getRateResponse1" /> </operation> </portType> <binding name="net.xmethods.services.currencyexchange.CurrencyExchangeBinding" type="tns:net.xmethods.services.currencyexchange.CurrencyExchangePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="getRate"> <soap:operation soapAction="urn:xmethods-CurrencyExchange#getRate" /> <input> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> </binding> <service name="net.xmethods.services.currencyexchange.CurrencyExchangeService"> <documentation> net.xmethods.services.currencyexchange.CurrencyExchange web service </documentation> <port name="net.xmethods.services.currencyexchange.CurrencyExchangePort" binding="tns:net.xmethods.services.currencyexchange. CurrencyExchangeBinding"> <soap:address location="http://206.135.115.109:9090/soap" /> </port> </service> </definitions>
This is the WSDL file for an exchange rate service implemented in Glue from The Mind Electric. Therefore, the format is not identical to a Microsoft SOAP Toolkit WSDL file, but it is compatible. The first element of the WSDL file is the definitions element, which is the root element of the file and normally contains several namespace declarations:
<definitions name="net.xmethods.services.currencyexchange.CurrencyExchange" targetNamespace="http://www.themindelectric.com/wsdl/ net.xmethods.services.currencyexchange.CurrencyExchange/" xmlns:tns="http://www.themindelectric.com/wsdl/ net.xmethods.services.currencyexchange.CurrencyExchange/" xmlns:electric="http://www.themindelectric.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> </definitions>
Note that the xsd namespace is the 2001 version. The SOAP Toolkit defaults to the 2001 Recommendation version of the XSD Schema namespace but it can understand WSDL files written with older namespace versions.
If the WSDL used any complex types, the XSD Schema definition for these types would be contained in a <types></types> element. Since this WSDL file doesn't use any complex types, that element is missing.
The next section defines the messages used by the service defined in this WSDL:
<message name="getRateRequest1"> <part name="country1" type="xsd:string" /> <part name="country2" type="xsd:string" /> </message> <message name="getRateResponse1"> <part name="Result" type="xsd:float" /> </message>
The names and datatypes of the method parameters are defined here.
The portType element defines a mapping between the messages defined in the previous section and the operations that use them:
<portType name="net.xmethods.services.currencyexchange.CurrencyExchangePortType"> <operation name="getRate" parameterOrder="country1 country2"> <input message="tns:getRateRequest1" /> <output message="tns:getRateResponse1" /> </operation> </portType>
The binding element defines a binding between the abstract operations defined in the portType element and how they are implemented in SOAP. This is done is a separate element because WSDL is intended to define other non-SOAP protocols. A few thing to note here: the style="rpc" means that this message uses the rpc rules defined in section 7 of the SOAP standard. If style="document" was specified, the contents of the SOAP message would be an XML document. The transport attribute indicates that the SOAP messages will be sent in SOAP HTTP messages, the soapAction attribute defines the contents of the soapAction header in the HTTP packet, and the use="encoded" attribute indicates that SOAP section 5 encoding is used for parameter values.
<binding name= "net.xmethods.services.currencyexchange.CurrencyExchangeBinding" type="tns:net.xmethods.services.currencyexchange.CurrencyExchangePortType"> <soap:binding style= "rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="getRate"> <soap:operation soapAction="urn:xmethods-CurrencyExchange#getRate" /> <input> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> </binding>
The service element ties a SOAP binding to a physical implementation of the service. This is where the URL of the service is defined. Notice that this service is found at port 9090—SOAP doesn't just work through port 80. (There is also a copy of the service running on port 80 if your firewall requires you to use port 80.)
<service name="net.xmethods.services.currencyexchange.CurrencyExchangeService"> <documentation> net.xmethods.services.currencyexchange.CurrencyExchange web service </documentation> <port name="net.xmethods.services.currencyexchange.CurrencyExchangePort" binding="tns:net.xmethods.services. currencyexchange.CurrencyExchangeBinding"> <soap:address location="http://206.135.115.109:9090/soap" /> </port> </service>
This section walks through the process of building a simple SOAP application using the SOAP Client included in Windows XP. The Web Service used in our example is the currency exchange rate service located at the XMethods site, an online listing of available SOAP services.
This service accepts two countries as parameters and returns the exchange rate between them. The WSDL file that describes this service is available at: http://www.xmethods.net/sd/CurrencyExchangeService.wsdl.
The steps necessary to call this SOAP method using the high-level SOAP API are: create a SOAPClient object, initialize the SOAPClient object with the WSDL file, and call the method.
Here's the simple VBScript code that accomplishes this:
dim SOAPClient set SOAPClient = createobject("MSSOAP.SOAPClient") on error resume next SOAPClient.mssoapinit("http://www.xmethods.net/sd/ CurrencyExchangeService.wsdl") if err then wscript.echo SOAPClient.faultString wscript.echo SOAPClient.detail end if wscript.echo SOAPClient.getRate("England","Japan") if err then wscript.echo SOAPClient.faultString wscript.echo SOAPClient.detail end if
The three bold lines correspond to the three steps mentioned previously. The parameter to mssoapinit is a WSDL file specification, which can be either an URL if the WSDL file is located on a remote system or a file path if the WSDL file is present on the local machine. A local WSDL file is more efficient because no network round-trips are necessary to retrieve the file. Still, it is easier to administer a single WSDL file that gets loaded to all the clients as it is used.
To run this SOAP method, type the code into a file called "currency.vbs" and then execute it with "cscript currency.vbs". The results should look something like this:
C:\SOAPDemo>cscript currency.vbs Microsoft (R) Windows Script Host Version 5.1 for Windows Copyright (C) Microsoft Corporation 1996-1999. All rights reserved. 173.9434
You should easily be able to apply this to VB, C++, or any other COM-enabled language. Here's the same service implemented in VB:
Private Sub Form_Load() Dim SOAPClient As SOAPClient Set SOAPClient = New SOAPClient On Error GoTo SOAPError SOAPClient.mssoapinit _ ("http://services.xmethods.net/soap/urn:xmethods-CurrencyExchange.wsdl") MsgBox Str(SOAPClient.getRate("England", "Japan")), _ vbOKOnly, "Exchange Rate" Exit Sub SOAPError: MsgBox SOAPClient.faultstring + vbCrLf + SOAPClient.detail, vbOKOnly,_ "SOAP Error" End Sub
Note:
The version of the SOAPClient that is included in Windows XP is not suitable for running in an ASP application. To do that, you must download the full release of the SOAP Toolkit 2.0.
Now that you know how to build a Web Services client application using SOAP in Windows XP, you might want to expand your SOAP knowledge and build Web Services of your own. Two good sources of information are http://msdn.microsoft.com/soap/ and http://msdn.microsoft.com/webservices/. These sites have links to SOAP information, white papers, other SOAP sites, and the download page where you can download the complete SOAP Toolkit 2.0 to start building your own Web Service applications. Please note that when you install the full release you will get some warnings about the inability to overwrite the current files because of system file protection. It is safe to ignore these errors. You can also go to XMethods and try some more of the services there—just keep in mind that in order for the SOAP Toolkit to work, the service must supply a WSDL file.
This section reviews the object model exposed by the SOAPClient object. Each method and property exposed by the SOAPClient is described. For more information, see http://msdn.microsoft.com/soap/.
The mssoapinit method initializes the SOAPClient object using the Web Services Description Language (WSDL) file as input. All of the operations in the identified service are bound to the SOAPClient object during initialization. Thus, you can call the operations defined in the service using the SOAPClient object.
HRESULT mssoapinit( [in] BSTR bstrWSDLFile, [in, optional, defaultvalue("")] BSTR bstrServiceName, [in, optional, defaultvalue("")] BSTR bstrPort, [in, optional, defaultvalue("")] BSTR bstrWSMLFile);
bstrWSDLFile
bstrWSDLFile is the URL of the WSDL file that describes the services offered by the server.
bstrServiceName
bstrServiceName is the optional service in the WSDL file that contains the operation specified in the Simple Object Access Protocol (SOAP) request. If this parameter is missing, null, or an empty string, the mssoapinit method uses the first service in the specified WSDL file when initializing the SOAPClient object.
bstrPort
bstrPort, also optional, is the name of the port in the WSDL file that contains the operation specified in the SOAP request. If this parameter is missing, null, or an empty string, the mssoapinit method uses the first port in the specified service when initializing the SOAPClient object.
bstrWSMLFile, also optional, is the URL of the Web Services Meta Language (WSML) file. This is a required parameter only when using custom type mappers.
Sub mssoapinit(bstrWSDLFile As String,_ [bstrServiceName As String],_ [bstrPort As String],_ [bstrWSMLFile As String])
set soapclient = CreateObject("MSSOAP.SOAPClient") call soapclient.mssoapinit("DocSample1.wsdl", "", "", "") wscript.echo soapclient.AddNumbers(2,3) wscript.echo soapclient.SubtractNumbers(3,2)
The mssoapinit method is part of the high-level API on the client side. To use this method, you must first create a SOAPClient object on the client. Then, call the mssoapinit method using the WSDL file name, service name, and port name as parameters. Now the client can call any operations defined in the WSDL file for the requested service or port.
The ClientProperty property sets and retrieves properties specific to the SOAPClient object.
[propget] HRESULT ClientProperty( [in] BSTR PropertyName, [out, retval] VARIANT* pPropertyValue); [propput] HRESULT ClientProperty( [in] BSTR PropertyName, [in] VARIANT pPropertyValue);
PropertyName PropertyName is the name of the property to set or retrieve. See the following Remarks section for a list of properties. The following properties are supported (the property names are case sensitive):
Property Name | Description |
---|---|
ServerHTTPRequest | A True/False value indicating whether to use the "server-safe" XML components to load the Web Services Description Language (WSDL) and Web Services Meta Language (WSML) files. Set to True when an Active Server Pages (ASP) application or an ISAPI DLL uses the SOAPClient object. When ServerHTTPRequest is set to true, the WinHTTP Proxy Configuration Utility must be used to configure WinHTTP. This is necessary even if a proxy server is not being used. Download utility and follow the usage instructions provided in the ReadMe.txt file provided in the download. |
ConnectorProgID | Specifies the ProgID of a class that implements the ISOAPConnector interface. Will create and use objects of this class when sending requests to the service. When set to an empty string, the default value, SOAPClient uses a SOAPConnectorFactory object to create a connector for the transport protocol specified the WSDL. |
pPropertyValue
pPropertyValue is the property's value.
Property ClientProperty(PropertyName As String) As Variant
Dim Client As New SOAPClient Client.ClientProperty("ServerHTTPRequest") = True
Sets and retrieves properties specific to the transport protocol connector used by a SOAPClient object.
[propget] HRESULT ConnectorProperty ( [in] BSTR PropertyName, [out, retval] VARIANT* pPropertyValue); [propput] HRESULT ConnectorProperty ( [in] BSTR PropertyName, [in] VARIANT pPropertyValue);
PropertyName
PropertyName is the name of the property to set or retrieve. Which properties are supported depends on the connector being used. The protocol specified by the <soap:binding> transport attribute in the Web Services Description Language (WSDL) file determines the connector to use.
pPropertyValue
pPropertyValue is the value of the property.
Property ConnectorProperty(PropertyName As String)
Dim Client As New SOAPClient Client.mssoapinit WSDLFile, Service, Port Client.ConnectorProperty("ProxyUser") = User Client.ConnectorProperty("ProxyPassword") = Password
Property | Description |
AuthPassword | The password used for end point authentication. |
AuthUser | The user name used for end point authentication. |
EndPointURL | The end point URL. |
ProxyPassword | The password used for proxy authentication. |
ProxyPort | The port of the proxy server to use. |
ProxyServer | The IP address or host name of the proxy server. |
ProxyUser | The user name used for proxy authentication. |
SOAPAction | The value used in the SOAPAction HTTP header. |
SSLClientCertificateName | A string identifying the client certificate to use for the Secure Sockets Layer (SSL) protocol, if any. The syntax is:
[CURRENT_USER | LOCAL_MACHINE\[store-name\]]cert-name with the defaults being CURRENT_USER\MY (the same store that Microsoft Internet Explorer uses). |
Timeout | The timeout for HttpConnector. This timeout is in milliseconds. |
UseSSL | A Boolean value (true or false) that specifies the use of SSL. |
The detail property is read-only. It provides the value of the <detail> element of the <Fault> element in the Simple Object Access Protocol (SOAP) message.
[propget] HRESULT detail( [out, retval] BSTR* bstrDetail);
bstrDetail
bstrDetail is the detail of the fault.
Property detail As String
Sets the header handler for the next call against this client instance.
HRESULT HeaderHandler([in] IDispatch* rhs);
rhs
rhs is the reference to the COM class interface that implements the IHeaderHandler.
Property HeaderHandler As Object
Set sc = WScript.CreateObject("MSSOAP.SOAPClient") sc.mssoapinit "http://localhost/DocSample7/DocSample7.wsdl" sc.HeaderHandler = WScript.CreateObject("SessionInfoClient.clientHeaderHandler") Sc.SomeMethod "param1", "param2"
The faultactor property is read-only, and provides the Universal Resource Identifier (URI) that generated the fault.
[propget] HRESULT faultactor( [out, retval] BSTR* bstrActor);
bstrActor
The bstrActor is the URI that generated the fault.
Property faultactor As String
wscript.echo soapclient.faultactor
The faultcode property is read-only. It provides the value of the <faultcode> element of the <Fault> element in the Simple Object Access Protocol (SOAP) message.
[propget] HRESULT faultcode( [out, retval] BSTR* bstrFaultcode);
bstrFaultcode
bstrFaultcode is the value of the <faultcode> element.
Property faultcode As String
wscript.echo soapclient.faultcode
This faultstring property is read-only. It provides the value of the <faultstring> element of the <Fault> element in the Simple Object Access Protocol (SOAP) message.
[propget] HRESULT faultstring( [out, retval] BSTR* bstrFaultstring);
bstrFaultstring
bstrFaultstring is the value of the <faultstring> element.
Property faultstring As String
wscript.echo soapclient.faultstring