This post contains attachments v20020425121357.zip 
Summary
Soap is emerging as a very popular protocol for exchanging information. It's relatively simple and designed to work with HTTP, SMTP and other such protocols. This article shows you how to use the Microsoft SOAP Tookit to develop a simple SOAP Client using C++.
Section 1: Prerequisites
You should be familiar with using COM, specially using Smart Pointers in COM
as I used import directive to convert COM interfaces to Smart Pointers. You
must have Microsoft SOAP Toolkit and Microsoft XML Parser installed on your system. For information on
downloading the toolkit, see Resources.
Section 2: Fundamentals of SOAP Programming
I'll start with the introduction of the classes involved in a basic SOAP Application.
Before that, we have to import the required type libraries so that our program
should be able to use the SOAP classes.
Importing Type libraries:
All the object and interfaces used in SOAP are found in mssoap1.dll. This file
is installed with the Microsoft SOAP Toolkit 2.0. You can find this file in
C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll. All you have to
do is to import this file into your source using the #import directive, which
is used to incorporate information from a type library. The contents of the
type library are converted into COM smart pointers, describing the COM interfaces.
Since SOAP relies completely on XML, therefore the Microsoft XML Parser is also
needed for XML processing. The Microsoft XML parser is included in msxml3.dll
where # is the version number. Again you need to import this file before importing
mssoap1.dll.
#import msxml3.dll
using namespace MSXML2;
#import C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll \
exclude(IStream, ISequentialStream, _LARGE_INTEGER, \
_ULARGE_INTEGER, tagSTATSTG, _FILETIME)
using namespace MSSOAPLib;
That is all what is needed to include all class definitions required to develop
a SOAP program. There are three steps that are necessary for making a SOAP client.
1- Specifying and connecting with the Web Service.
2- Prepare and Send the Message
3- Reading the response back from the Service
Now lets take a look at the classes involved. Following are the classes that
are used to develop a basic SOAP Client
1- SoapConnector:
The first thing that is required for any client in a client/ server application
is to connect with the server. The SoapConnector class implements the protocol
that is used as a transport between the client and the server. SoapConnector
acts as an abstract class for defining interface for implementing other protocols.
That is for the fact that SOAP is not limited to a specific protocol, as you'll
see that some implementation supports MSMQ, MQ Series, SMTP and TCP/IP Transports.
For the sake of simplicity, I am demonstrating the use of HTTP Transport, which
is implemented by the HttpConnector class available with the Microsoft SOAP
Toolkit 2.0.
The steps involved in using SoapConnector class.
a) Creating a object to SoapConnector:
ISoapConnectorPtr connector; Connector.CreateInstance(__uuidof(HttpConnector));
b) Specifying the Web Service Address:
Next, we have to define the web service that we are using as a client. The
service is specified using the Property (an attribute of HttpConnector). There
are two things to specify when dealing with this attribute, that is 1) which
property are we referring to and 2) the value of the respective property type.
Here, for specifying the web service, we use the EndPointURL property.
Connector->Property [EndPointURL] = some url pointing to web service;
The following table provides a list of properties (The property names are case
sensitive).
|
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. This property
can be set only from the low-level API. It is ignored if the property is
set using the ConnectorProperty property of the SoapClient interface (high-level
API) |
|
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. |
|
UseProxy
|
A Boolean property that specifies whether a to use a proxy server. By
default, this property is set to False indicating that a proxy server should
not be used. Set this property to True if you want to use a proxy server.
If you set this property to True and don't specify the ProxyServer property,
then the HttpConnector uses the proxy server set in the default settings
of Microsoft® Internet Explorer. In this release, the HttpConnector
ignores the Bypass Proxy settings in Internet Explorer.
|
|
UseSSL
|
A Boolean value (True or False) that specifies the use of SSL.
If this property is set to True, the HttpConnector object uses SSL connection
regardless of whether HTTP or HTTPS is specified in the WSDL. If this property
is set to False, the HttpConnector object will use SSL connection only if
HTTPS is specified in the WSDL.
|
( The above table is taken from MSDN )
c) Connecting with the Web Service:
The connect method of HttpConnector is used to initialize the SoapConnector
object and actually prepares a connection with the service.
Connector->Connect();
d) Specifying the action:
After connecting with the server, we need to specify the action that we are
going to perform on the web service. To specify the Action, we again use the
Property attribute of the SoapConnector
Connector->Property [SoapAction] = some uri;
e) Message Handling:
After connecting with the service and specifying other details , we signal
the start of a SOAP message being sent to the server. The function must be called
before calling any other method of SoapSerializer ( which is used to prepare
message).
Connector->BeginMessage();
After finishing with the message, we must call the EndMessage() function to
actually send the message to the service.
.
.
[ message preparation code ]
.
.
Connector->EndMessage();
This is all that is needed to actually connect with the service, the next part
shows you how to create and prepare a message.
SoapSerializer:
The SoapSerializer is used to build a SOAP message to be sent to the service.
The SoapSerializer object must be connected with the SoapConnector object before
communicating with the server. To interconnect these two objects, we need to
call the Init method of the SoapSerializer object. This method takes a single
argument, which is the InputStream (the stream the sends data to the server).
// creating a SoapSerializer object and initializing it with InputSTream
ISoapSerializerPtr Serializer; Serializer.CreateInstance(_uuidof(SoapSerializer));
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
Before looking into other functions of SoapSerializer , lets take a look at
a sample SOAP Request to get an idea of what we are building in our code.
Simple Soap Request:
<SOAP: Envelope xmlns:SOAP=soap namespace>
<SOAP:Body>
<m:someMethodName xmlns:m=some namespace>
<someParameter> someParameterValue </someParameter>
<m:someMethodName>
</SOAP:Body>
</SOAP: Envelope>
A soap request is simply encapsulated into tags. <Envelope> tag is the
main tag of this SOAP Document. A Soap Message is always encapsulated in an
Envelope. The Envelope contains a Message Body, which is specified by a <Body>
Tag. The Body contains the actual request. In C++, we have the appropriate methods
to create these tags and specify any values in these. The following code piece
demonstrates the use of these methods.
Serializer->startEnvelope(SOAP,,);
// begins an element in a SOAP message, first argument defines the
namespace, if it
// is empty then SOAP-ENV is used by default, the second and the third argument
defines the URI
// and the Encoding Type respectively Serialzier->startBody();
// begins the <Body> element in the message, the first argument defines
the encoding style Uri,
// by default it is NONE.
Serializer->startElement(someMethodName,,,m);
// Begins a child element into the body element of a SOAP message, the first
parameter is the
// element name, the second parameter is the Uri, third is encoding style and
the last element
// is the namespace for the element.
Serializer->WriteString(someParameterValue)
// writes the value of an element.
All the above startXXX functions have their equivalent endXXX function to end
the element. After finishing with the message, the connector's endMessage()
method is called to actually send the message as described above.
Till now in this tutorial, we have connected with the service, prepared our
request and send it to service. The next and the final step is to read the response
from the server.
SoapReader:
This object reads the response from the service and parses the incoming message
into DOM for further processing. Following is a sample SOAP Response from the
service.
Simple SOAP Response:
<SOAP: Envelope xmlns:SOAP=soap namespace>
<SOAP:Body>
<m:someMethodNameResponse xmlns:m=some namespace>
<return> someResult </return>
<m:someMethodNameResponse>
</SOAP:Body>
</SOAP: Envelope>
Before calling any functions to get the result, we connect with the OutputStream
to actually read the response in a SoapReader object. ( An OutputStream receives
data from the service ).
// code to create a SOAPReader object and connecting with the outputstream
ISoapReaderPtr Reader; Reader.CreateInstance(_uuidof(SoapReader)); Reader->Load(_variant_t((IUnknown*)Connector->OutputStream));
// the load method can also accept a XML Document File or String
After loading the response into our SoapReader object, we get the result by
calling the RPCResult property of SoapReader object. But RPCResult doesn't return
the actual result; it returns the first child element of the first entry in
the <Body> element. We get the result by calling the text property.
Reader->RPCResult->text
Section 3: Demonstrating a Sample SOAP Client
For demonstrating the use of above SOAP classes, I used one of the services
listed on www.xmethods.net. The service indicates Yahoo Messenger's online presence.
You can find the required details by following this URL. http://www.xmethods.net/ve2/ViewListing.po?serviceid=156.
The only thing it expects is a method parameter i.e. the Yahoo user's login
id. The result returned is a Boolean value indicating 0 for offline and 1 for
online. Other details are available on the site or by viewing the wsdl at http://www.allesta.net:51110/webservices/wsdl/YahooUserPingService.xml
Section 4:
Resources:
The SOAP specification Simple Object Access Protocol (SOAP) 1.1 - W3C Note
http://www.w3.org/TR/SOAP
Microsoft SOAP Toolkit Download
http://download.microsoft.com/download/xml/soap/2.0/w98nt42kme/EN-US/SoapToolkit20.exe
|