Download source files - 3 Kb
Download demo project - 25 Kb
Introduction
SOAP has a lot of potential for providing interfaces for web services.
SOAP will be good for a lot of different types of services. The SOAP toolkit
from Microsoft provides developers with a good starting place for learning SOAP.
The SOAP Toolkit 2.0 Beta 1 was released on Jan 3, 2000. It provides new samples
and a help file to explain the new interfaces. The samples provide both client
and server examples to build from in developing your own services.
One thing that is a bit neglectd in the samples (provided by Microsoft) is the
use of C++ to develop the services. All of the samples are written to show the
use of VB and ASP. This is fine and dandy, but from the use of SOAP my work needs
to use C++. So I looked on the Internet for examples of SOAP using VC. To my
surprise, I only found one, and it used the SOAP Toolkit 1.0 instead of the latest 2.0.
Since the VB samples worked perfectly fine, I decided to develop a client application
using VC to talk to the VB Web Service. I started with the Low-Level VB Calculator
program and the VC sample that I had from the SOAP Toolkit 1.0.
To include the COM interfaces from the SOAP DLLs, the #import
directive was used. This was used for the MSSOAP1.dll and a using clause was added to use
the MSSOAPLib namespace. The VB sample used a WinInetConnector to connect to the webserver
for the service. This interface is not in the MSSOAPLib namespace. WiSC10.dll was also
imported so that I had the connector that was needed.
This second import led to problems. I had never had to import more than one DLL in any of my
previous projects. I was getting a fatal error LNK1179: invalid or corrupt file: duplicate comdat
"_IID_ISoapConnector"
link error. After some research,
I found that I had to remove the named_guids
from the second import line. This
solved my linking error and allowed the rest of the coding to go a lot smoother. An
exclude
statement was included to remove some compiler warnings about automatic excludes.
#import "C:\\Program Files\\MSSoapSDK\\Binaries\\MSSOAP1.dll" named_guids raw_interfaces_only exclude("IStream","ISequentialStream","_LARGE_INTEGER","_ULARGE_INTEGER","tagSTATSTG","_FILETIME")
#import "C:\\Program Files\\MSSoapSDK\\Binaries\\WiSC10.dll" raw_interfaces_only exclude("IStream","ISequentialStream","_LARGE_INTEGER","_ULARGE_INTEGER","tagSTATSTG","_FILETIME")
using namespace MSSOAPLib;
From here, the rest of the conversion from the VB code to the C++ interfaces was simple. This
was fairly straight forward for anyone that has done conversions before. Smart pointers were
used to make the creating and releasing of objects simpler.
SOAP Client Summary
For this VC example, I decided to use the one VC sample that I had found online as a base for
development. The problem with this is that it was a console application and not a windowed
application. I decided to still develop it using the console based app and just stick with
one type of command to the server. Including this code into a normal Window application should
be a trivial thing for most VC COM developers.
To begin this low-level SOAP client, you need to create a SoapConnector. The implementation of
the SoapConnector could use any type of transport protocol such as HTTP, FTP, or SMTP. The
SOAP documentation says that there are three different SoapConnector implementations included
with the SOAP Toolkit 2.0. These implementations are WinInetConnector, XmlHttpConnector (default
for 9x/Me clients), and HttpLibConnector (default for NT/2K clients). I choose to use the
WinInetConnector since the VB sample that I was basing my code on used it. I went back to try the
other implemetations of the SoapConnector and all of them worked correctly on Win2k.
Connector = NULL;
Connector.CreateInstance(__uuidof(WinInetConnectorLib::WinInetConnector));
Connector->put_Property(endpoint,vEndPoint);
Connector->Connect(NULL);
Connector->put_Property(action,vAction);
Connector->BeginMessage(NULL);
After creating the SoapConnector, the EndPointURL
was set and the Connect
method was called. This allows the code to connect to the web service. The SoapAction
was then set to uri:Multiply
to tell the server what action I was going to be requesting.
This follows the VB example from the toolkit.
The next step is to create the SoapSerializer. The SoapSerializer is the interface that allows you to
create the XML message and send it to the server.
Serializer = NULL;
Serializer.CreateInstance(__uuidof(SoapSerializer));
Connector->get_InputStream(&inputstream);
_variant_t stream = inputstream;
Serializer->Init(stream);
Serializer->startEnvelope(NULL,NULL,NULL);
Serializer->startBody(NULL);
Serializer->startElement(method,command,NULL,m);
Serializer->startElement(a,NULL,NULL,NULL);
Serializer->writeString(val1);
Serializer->endElement();
Serializer->startElement(b,NULL,NULL,NULL);
Serializer->writeString(val2);
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
Connector->EndMessage();
After the SoapSerializer is created, it needs to be attached to the input stream of the SoapConnector.
After this, the message is created and sent. As an interesting note, as you look over the source code,
the EndMessage
method is the command that sends the message to the server.
Up to this point, we have built the XML command and sent it to the server to be executed. The next step
is to read the results. I left error checking off for this, but it can be added. To read the reply from
the server the client application needs to use a SoapReader. The SoapReader is connected to the output
stream of the SoapConnector. From there, the results can be read back in using an IXMLDOMElement object.
This is then displayed using std::cout
.
Reader = NULL;
Reader.CreateInstance(__uuidof(SoapReader));
Connector->get_OutputStream(&outputstream);
_variant_t outstream = outputstream;
VARIANT_BOOL bres;
Reader->load(outstream,&bres);
MSSOAPLib::IXMLDOMElement *element;
Reader->get_RPCResult(&element);
BSTR buff;
element->get_baseName(&buff);
std::cout << W2A(buff) << std::endl;
element->get_text(&buff);
std::cout << W2A(buff) << std::endl;
Conclusion
Overall, SOAP communications is a simple thing for most developments. The low-level communications shown
here allows you to see the creation of the XML message as well as parse out the return message. This is a
simple example based on the ClcLVBCl sample that comes with the SOAP Toolkit 2.0 that shows the way that
SOAP can be used with VC.