分享
 
 
 

Writing Web Services Client Applications using Visual C++

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Writing Web Services Client Applications using Visual C++

Abstract:

XML Web Services is rapidly becoming the technology of choice for distributed application and application-integration, over Internet. The caller application uses the standard protocol (such as HTTP or SMTP) to send specially-formatted XML messages (known as SOAP request envelope); the server application in turn does the processing and sends back the results also as specially formatted XML message (known as SOAP response envelope). The standards-based notion of Web Services enables these two applications; possibly residing on two totally different platforms, and written using varied programming languages and tools; to interact without and platform- or programming language-worries. XML Web Services is receiving more and more vendor and tools support, and the technology itself is maturing rapidly. Microsoft, IBM, and others are working to define the essential layers (such as security, transaction-support, Web Services reliability, coordination and routing) over Web Services.

This article illustrates writing XML Web Services client applications in Visual C++, using Microsoft XML Core Services (or MSXML), Microsoft SOAP Toolkit Version 3, and PocketSOAP.

The first example uses the MSXML XMLHTTP component to invoke a Web Service written using Apache SOAP.

The second example uses the MSXML ServerXMLHTTP component to invoke a Web Service written using (ASP).NET. This example illustrates calling a Web Service using HTTP GET, HTTP POST, and SOAP.

The third example uses Microsoft SOAP Toolkit Version 3 high-level API to invoke a Web Service written using GLUE.

The fourth example uses Microsoft SOAP Toolkit Version 3 low-level API to invoke a Web Service written using (ASP).NET.

The fifth, and final, C++ sample application illustrates using PocketSOAP to call a .NET Web Service.

All the sample applications in this article are Win32 console applications written using C++ and created using Microsoft Visual Studio 6.0. The first two applications use MSXML 4, next two (third and fourth) sample applications use SOAP Toolkit version 3, and the fifth application uses PocketSOAP. Be sure to download and install these libraries to successfully run the code samples provided with this article.

Author:

Darshan Singh (Managing Editor, PerfectXML.com)

Last Updated:

February 02, 2003

Download:

CPPSOAP.zip (353 KB ZIP file)

1. Using MSXML XMLHTTP MSXML, the premier XML processing component from Microsoft, is shipped with various versions of Internet Explorer (for example, IE 6.0 ships MSXML version 3 SP2); and is also available as a separate download from the MSDN Web site. If you are writing a C++ desktop client application and need to call a Web Service, one option is to use the XMLHTTP component inside MSXML. XMLHTTP, a COM wrapper around WinInet (the core HTTP API used by Internet Explorer), allows sending HTTP GET and POST requests and process the response. XMLHTTP is designed to be used on the client-side, and should not be used inside server applications to send HTTP requests to other servers. If you are writing a server-side application, and need to call a Web Service, refer to example 2 below, which uses ServerXMLHTTP. This first sample application uses MSXML XMLHTTP to POST a SOAP request to the Weather ?Temperature Web Service on the XMethods Web site.

The header file (XMLHTTP1.h):

#ifndef _XMLHTTP1_H_

#define _XMLHTTP1_H_

#include <atlbase.h>

#import <msxml4.dll> named_guids

using namespace MSXML2;

#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }

// SOAP Endpoint URL

static const TCHAR* const g_lpszSOAPEndpointURL =

_T("http://services.xmethods.net:80/soap/servlet/rpcrouter");

// SOAP Request to be posted

static const TCHAR* const g_lpszSOAPReq = _T(

"<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' "

"xmlns:xsi='http://www.w3.org/1999/XMLSchema-instance' "

"xmlns:xsd='http://www.w3.org/1999/XMLSchema'> "

"<SOAP-ENV:Body> "

"<ns1:getTemp xmlns:ns1='urn:xmethods-Temperature' "

" SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'> "

"<zipcode xsi:type='xsd:string'>%s</zipcode> "

"</ns1:getTemp> "

"</SOAP-ENV:Body> "

"</SOAP-ENV:Envelope> ");

#endif // _XMLHTTP1_H_

The source code file (XMLHTTP1.cpp)

#include "stdafx.h"

#include "XMLHTTP1.h"

//------------------------------------------------------------------------------

// Function uses XMLHTTP to POST a SOAP request to the Temprature Web Service

// and then uses MSXML DOM to process the SOAP response XML text.

//------------------------------------------------------------------------------

float CallWebService(LPCTSTR szZipCode)

{

float fTemprature = -999;

USES_CONVERSION;

// SOAP Request Envelop to be posted

TCHAR szSOAPReq[MAX_PATH*2] = {0};

sprintf(szSOAPReq, g_lpszSOAPReq, szZipCode);

//printf(szSOAPReq);

// Create an instance of XMLHTTP Class

CComPtr<IXMLHTTPRequest> spXMLHTTP;

HRESULT hr = spXMLHTTP.CoCreateInstance(CLSID_XMLHTTP40);

CHECK_HR(hr);

// Initialize the Synchronous HTTP POST request

hr = spXMLHTTP->open(_bstr_t(_T("POST")), g_lpszSOAPEndpointURL, VARIANT_FALSE);

CHECK_HR(hr);

// Set the required Content-Type header

hr = spXMLHTTP->setRequestHeader(_bstr_t(_T("Content-Type")), _bstr_t(_T("text/xml")));

CHECK_HR(hr);

// Send the POST request, along with the SOAP request envelope text

hr = spXMLHTTP->send(_bstr_t(szSOAPReq));

CHECK_HR(hr);

if(200 == spXMLHTTP->status) //Success

{

// using MSXML DOM to process SOAP response XML text

CComQIPtr <IXMLDOMDocument2> spResponseXMLDoc;

CComPtr <IXMLDOMNode> spResultNode;

spResponseXMLDoc = spXMLHTTP->responseXML;

spResultNode = spResponseXMLDoc->selectSingleNode(_bstr_t(_T("//return")));

if(spResultNode.p != NULL)

{

fTemprature = spResultNode->nodeTypedValue;

}

}

else

{

printf(_T("\nError: %s\n"), W2A(spXMLHTTP->statusText));

}

return fTemprature;

}

// main, The entry point function

int main(int argc, char* argv[])

{

if(argc < 2)

{//insufficient parameters

printf(_T("\nXMLHTTP1.exe: Sample Web Service client to get the temprature for the given Zipcode.\n"));

printf(_T("\nUsage:\tXMLHTTP1.exe <US_Zipcode>\nExample: XMLHTTP1.exe 98007\n"));

return -1;

}

try

{

HRESULT hr = CoInitialize(NULL);

CHECK_HR(hr);

float fTemp = CallWebService((LPCTSTR)argv[1]);

if(fTemp != -999)

printf(_T("The temprature at zipcode %s is %.2f Fahrenheit.\nPress Enter to continue..."),

argv[1],fTemp);

else

printf(_T("\nError: Invalid Zipcode or failed to get the temprature at zipcode %s. "

"\nPress Enter to continue..."), argv[1]);

}

catch(int)

{

//TODO: Error handling

printf(_T("Exception raised!"));

}

CoUninitialize();

getchar();

return 0;

}

Output:

The header file declares the #import statement so that we can use MSXML4, and declares couple of constant strings (the SOAP endpoint URL and the SOAP request envelope). The main function in the CPP file calls a supporting function CallWebService and passes it the value of the command line parameter (the zip code). The supporting function CallWebService then formats the request SOAP envelope and posts it to the SOAP endpoint URL. The responseXML property contains the response SOAP envelope and the above application uses MSXML DOM and XPath to get the result value.

2. Using MSXML ServerXMLHTTP If you are writing a server-side application (such as an ISAPI DLL or a COM DLL to be loaded on the server side), and need to invoke a XML Web Service, you can use MSXML ServerXMLHTTP component. The following sample C++ application illustrates using MSXML ServerXMLHTTP to invoke a .NET Web Service, either by sending HTTP GET request, or HTTP POST request, or posting SOAP and processing the SOAP response. This sample application invokes the Weather Info XML Web Service to get the detailed weather information for any given valid US zip code.

The header file (ServerXMLHTTP1.h):

#ifndef _SERVERXMLHTTP1_H_

#define _SERVERXMLHTTP1_H_

#include <atlbase.h>

#import <msxml4.dll> named_guids

using namespace MSXML2;

#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }

// --------------------------------------------------------

static const TCHAR* const g_lpszGetURL =

_T("http://www.ejse.com/WeatherService/Service.asmx/GetWeatherInfo?zipCode=%s");

// --------------------------------------------------------

static const TCHAR* const g_lpszPostURL =

_T("http://www.ejse.com/WeatherService/Service.asmx/GetWeatherInfo");

// --------------------------------------------------------

static const TCHAR* const g_lpszSOAPEndpointURL =

_T("http://www.ejse.com/WeatherService/Service.asmx");

static const TCHAR* const g_lpszSOAPAction =

_T("http://ejse.com/WeatherService/GetWeatherInfo");

static const TCHAR* const g_lpszSOAPReq =

_T("<?xml version='1.0' encoding='utf-8'?> "

"<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>"

" <GetWeatherInfo xmlns='http://ejse.com/WeatherService/'>"

" <zipCode>%s</zipCode>"

" </GetWeatherInfo>"

" </soap:Body>"

"</soap:Envelope>");

// --------------------------------------------------------

static const TCHAR* const g_lpszXPathSelNS =

_T("xmlns:ns1='http://ejse.com/WeatherService/'");

// --------------------------------------------------------

//TODO: Move to resource file

static const TCHAR* const g_lpszOutputMsg =

_T("Weather Information - Last Updated %s\n\n"

"\tLocation: %s (%s)\n\tTemprature: %s\n\tForecast: %s\n\t"

"Visibility: %s\n\tHumidity: %s\n\tPressure: %s\n");

// --------------------------------------------------------

#endif // _SERVERXMLHTTP1_H_

The source code file (ServerXMLHTTP1.cpp)

#include "stdafx.h"

#include "ServerXMLHTTP1.h"

// Utility function

void GetXPathExprValue(CComQIPtr<IXMLDOMDocument2> &spResponseXMLDoc,

LPCTSTR lpszXPathExpr,

LPSTR lpszResultValue)

{

USES_CONVERSION;

CComPtr <IXMLDOMNode> spResultNode;

spResultNode = spResponseXMLDoc->selectSingleNode(_bstr_t(lpszXPathExpr));

if(spResultNode.p != NULL)

_tcscpy(lpszResultValue, W2A(_bstr_t(spResultNode->nodeTypedValue)));

}

//------------------------------------------------------------------------------

// Function uses ServerXMLHTTP to send a GET/POST/SOAP request to a .NET Web Services,

// and then uses MSXML DOM to process the response XML text.

//

// Illustrates calling a .NET Web Service either by sending a GET request,

// or a HTTP POST or by using the SOAP method.

//

// iMethod parameter:

// 0 : (Default) HTTP GET

// 1 : HTTP POST

// 2 : SOAP

//------------------------------------------------------------------------------

void CallWebService(LPCTSTR szZipCode, int iMethod = 0)

{

float fTemprature = -999;

USES_CONVERSION;

// Create an instance of ServerXMLHTTP Class

CComPtr<IServerXMLHTTPRequest> spServerXMLHTTP1;

HRESULT hr = spServerXMLHTTP1.CoCreateInstance(CLSID_ServerXMLHTTP40);

CHECK_HR(hr);

TCHAR szGetURL[MAX_PATH*2]={0};

TCHAR szPostValue[MAX_PATH*2]={0};

TCHAR szSOAPReq[MAX_PATH*2]={0};

int iPostDataLen =0;

TCHAR szDataLen[10]={0};

switch(iMethod)

{

case 0: // HTTP GET

sprintf(szGetURL, g_lpszGetURL, szZipCode);

// Initialize the Synchronous HTTP GET request

hr = spServerXMLHTTP1->open(_bstr_t(_T("GET")), szGetURL, VARIANT_FALSE);

CHECK_HR(hr);

// Send the HTTP GET request

hr = spServerXMLHTTP1->send();

CHECK_HR(hr);

break;

case 1: // HTTP POST

_tcscpy(szPostValue, _T("zipCode="));

_tcscat(szPostValue, szZipCode);

iPostDataLen = _tcslen(szPostValue);

itoa(iPostDataLen, szDataLen, 10);

// Initialize the Synchronous HTTP GET request

hr = spServerXMLHTTP1->open(_bstr_t(_T("POST")), g_lpszPostURL, VARIANT_FALSE);

CHECK_HR(hr);

spServerXMLHTTP1->setRequestHeader(_T("Content-Type"),

_T("application/x-www-form-urlencoded"));

spServerXMLHTTP1->setRequestHeader(_T("Content-Length"), szDataLen);

// Send the HTTP POST request, along with the SOAP request envelope text

hr = spServerXMLHTTP1->send(szPostValue);

CHECK_HR(hr);

break;

case 2: // SOAP

sprintf(szSOAPReq, g_lpszSOAPReq, szZipCode);

hr = spServerXMLHTTP1->open(_bstr_t(_T("POST")), g_lpszSOAPEndpointURL, VARIANT_FALSE);

CHECK_HR(hr);

// Set the required SOAPAction and Content-Type headers

hr = spServerXMLHTTP1->setRequestHeader(_T("SOAPAction"), g_lpszSOAPAction);

CHECK_HR(hr);

hr = spServerXMLHTTP1->setRequestHeader(_bstr_t(_T("Content-Type")),

_bstr_t(_T("text/xml")));

CHECK_HR(hr);

// Send the POST request, along with the SOAP request envelope text

hr = spServerXMLHTTP1->send(_bstr_t(szSOAPReq));

CHECK_HR(hr);

break;

}

if(200 == spServerXMLHTTP1->status) //Success

{

// using MSXML DOM to process the response XML text

CComQIPtr <IXMLDOMDocument2> spResponseXMLDoc;

spResponseXMLDoc = spServerXMLHTTP1->responseXML;

spResponseXMLDoc->setProperty(_bstr_t(_T("SelectionNamespaces")), g_lpszXPathSelNS);

TCHAR szLastUpdated[MAX_PATH] = {0};

TCHAR szLocation[MAX_PATH] = {0};

TCHAR szReportedAt[MAX_PATH] = {0};

TCHAR szTemprature[MAX_PATH] = {0};

TCHAR szForecast[MAX_PATH] = {0};

TCHAR szVisibility[MAX_PATH] = {0};

TCHAR szHumidity[MAX_PATH] = {0};

TCHAR szPressure[MAX_PATH] = {0};

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:LastUpdated"), szLastUpdated);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Location"), szLocation);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:ReportedAt"), szReportedAt);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Temprature"), szTemprature);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Forecast"), szForecast);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Visibility"), szVisibility);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Humidity"), szHumidity);

GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Pressure"), szPressure);

printf(g_lpszOutputMsg, szLastUpdated, szReportedAt, szLocation,

szTemprature, szForecast, szVisibility, szHumidity, szPressure);

}

else

{

printf(_T("\nError: %s\n"), W2A(spServerXMLHTTP1->statusText));

}

}

// main, The entry point function

int main(int argc, char* argv[])

{

if(argc < 2)

{//insufficient parameters

printf(_T("\nServerXMLHTTP1.exe: Sample Web Service client to get "

" the weather information for a valid given U.S. zipcode\n"));

printf(_T("\nUsage:\tServerXMLHTTP1.exe <US_Zipcode> [<Method (0=GET, 1=POST, 2=SOAP)>]\n"

"Examples:\n\tServerXMLHTTP1.exe 98007\n\t"

"ServerXMLHTTP1.exe 98007 1"));

printf(_T("\n\nPress Enter to continue..."));

getchar();

return -1;

}

try

{

HRESULT hr = CoInitialize(NULL);

CHECK_HR(hr);

// The Method (GET[0]/POST[1]/SOAP[2])

int iCallMethod = 0;

if(argc >= 3 && argv[2] != NULL)

iCallMethod = atoi(argv[2]);

CallWebService((LPCTSTR)argv[1], iCallMethod);

}

catch(int)

{

//TODO: Error handling

printf(_T("Exception raised!"));

}

CoUninitialize();

printf(_T("\n\nPress Enter to continue..."));

getchar();

return 0;

}

Output:

The above sample application uses MSXML ServerXMLHTTP component to call a XML Web Service either by sending a HTTP GET, HTTP POST or a SOAP request. The iMethod parameter to the CallWebService supporting function decides which method to use while invoking the Web Service.

The header file imports the MSXML type library, and declares few strings used for sending the Web Service request and to process the response XML. The CPP source code file, first creates an instance of ServerXMLHTTP class, and then based on iMethod parameter, the switch statement sends the HTTP GET, POST, or SOAP request, and if the request was successful (HTTP status code = 200), responseXML DOM object and XPath expressions are used to get the returned weather information.

3. Using Microsoft SOAP Toolkit 3.0 (High-Level API) The Microsoft SOAP Toolkit is a set of COM components used to: invoke Web Services on the client-side, map Web Service method calls to the COM object methods, and to marshal and unmarshal (that is to create, transmit, read and process) SOAP messagesIn this article we'll keep the focus on invoking the Web Services using this toolkit. The SOAP toolkit offers high-level API and low-level API. As the names suggest, the high-level API hides the SOAP-messaging related details and you feel like you are calling a COM object; whereas, with the low-level API, you exactly know how the SOAP request and response messages will look like. To download the SOAP Toolkit and for more information on this, visit msdn.microsoft.com/soap.

The following sample application uses the Microsoft SOAP Toolkit version 3.0 high-level API to invoke Domain Name Checker Web Service to see if the specified domain name is availabe or not. Note that the SOAP Tookit has the dependancy on the MSXML, and hence the following header file imports MSXML typelib in addition to the SOAP toolkit type library.

The header file (SOAPToolkit1.h):

#ifndef _SOAPTOOLKIT1_H_

#define _SOAPTOOLKIT1_H_

#include "atlbase.h"

#import <msxml4.dll>

using namespace MSXML2;

#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" named_guids \

exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \

"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")

using namespace MSSOAPLib30;

#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }

// -----------------------------------------------------------------------

static const TCHAR* const g_lpszWSDL_URL =

_T("http://services.xmethods.net/soap/urn:xmethods-DomainChecker.wsdl");

// -----------------------------------------------------------------------

#endif // _SOAPTOOLKIT1_H_

The source code file (SOAPToolkit1.cpp)

#include "stdafx.h"

#include "SOAPToolkit1.h"

void CallWebService(_bstr_t bstrDomainName)

{

USES_CONVERSION;

CComPtr<ISoapClient> spSOAPClient;

HRESULT hr = spSOAPClient.CoCreateInstance(CLSID_SoapClient30);

CHECK_HR(hr);

hr = spSOAPClient->MSSoapInit(_bstr_t(g_lpszWSDL_URL),

L"", L"", L"");

CHECK_HR(hr);

// Call the Web Service method

WCHAR *pwcMethodName = L"checkDomain";

DISPID dispidFn = 0;

hr = spSOAPClient->GetIDsOfNames(IID_NULL, &pwcMethodName, 1,

LOCALE_SYSTEM_DEFAULT, &dispidFn);

CHECK_HR(hr);

unsigned int uArgErr;

VARIANT varg[1];

varg[0].vt = VT_BSTR;

varg[0].bstrVal = bstrDomainName;

DISPPARAMS params;

params.cArgs = 1;

params.rgvarg = varg;

params.cNamedArgs = 0;

params.rgdispidNamedArgs = NULL;

_variant_t result;

uArgErr = -1;

EXCEPINFO excepInfo;

memset(&excepInfo, 0, sizeof(excepInfo));

hr = spSOAPClient->Invoke(dispidFn, IID_NULL, LOCALE_SYSTEM_DEFAULT,

DISPATCH_METHOD, &params, &result, &excepInfo, &uArgErr);

CHECK_HR(hr);

if(result.vt = VT_BSTR)

{

printf(_T("Domain %s is %s."), W2A(bstrDomainName), W2A(result.bstrVal));

printf(_T("\n\nPress Enter to continue..."));

getchar();

}

}

int main(int argc, char* argv[])

{

if(argc < 2)

{//insufficient parameters

printf(_T("\nSOAPToolkit1.exe: Sample Web Service client to check "

" whether a domain name is available or not\n"));

printf(_T("\nUsage:\tSOAPToolkit1.exe <DomainName>\n"

"Examples:\n\tSOAPToolkit1.exe microsoft.com\n\t"

"SOAPToolkit1.exe mywebsiteurl.com"));

printf(_T("\n\nPress Enter to continue..."));

getchar();

return -1;

}

try

{

HRESULT hr = CoInitialize(NULL);

CHECK_HR(hr);

CallWebService(_bstr_t(argv[1]));

}

catch(int)

{

//TODO: Error handling

printf(_T("Exception raised!"));

}

CoUninitialize();

return 0;

}

Output:

The header file imports MSXML and SOAP Toolkit type libraries, and declares the Web Service WSDL URL string.

The SoapClient30 class is used to invoke the Web Services and this class is the basis of the SOAP toolkit high-level API. The CPP source code file above creates an instance of SoapClient30 class, followed by calling MSSoapInit member function, passing it the WSDL URL.

The MSSoapInit member function is used to initialize the SoapClient30 object using the WSDL file, and once we do this, the SoapClient30 instance can be used to call the Web Service method, like any other COM object that implements IDispatch interface. Once the SoapClient30 object is initialized using the WSDL file, IDispatch methods (GetIDsOfNames and Invoke) can be called on this object for any of the Web Service method. The above code illustrates this for the checkDomain Web Service method.

4. Using Microsoft SOAP Toolkit 3.0 (Low-Level API) The SOAP Toolkit low-level API provides the absolute control over the SOAP message serialization and transport. The SoapSerializer30 class is used to create the SOAP message. As in this example, we'll be calling a Web Service over HTTP, we use the HttpConnector30 class instance to send the SOAP request message and receive the SOAP response message, over HTTP. And finally, the SoapReader30 class is used to read the SOAP response message. The SoapReader30 class offers various methods and properties to easily read/parse/extract the information from the SOAP message. The following sample application uses Microsoft SOAP Toolkit 3.0 low-level API classes to invoke the SearchMusicTeachers Web Service, to find out the music teachers details in the given US zip code. Only Zip code value is accepted as the command line parameter, other values (such as instrument, result count restriction, radius, skill level, etc.) are hard-coded in this sample application.

The source code file (SOAPToolkitLowLevel.cpp):

#include "stdafx.h"

#include <stdio.h>

#include "atlbase.h"

#import <msxml4.dll>

using namespace MSXML2;

#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \

exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \

"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")

using namespace MSSOAPLib30;

void CallWebService(_bstr_t ZipCode)

{

ISoapSerializerPtr Serializer;

ISoapReaderPtr Reader;

ISoapConnectorPtr Connector;

HRESULT hr = S_OK;

hr = Connector.CreateInstance(__uuidof(HttpConnector30));

Connector->Property[_T("EndPointURL")] =

_T("http://www.PerfectXML.net/WebServices/MusicTeachers/MusicTeachers.asmx?wsdl");

hr = Connector->Connect();

Connector->Property[_T("SoapAction")] =

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/FindMusicTeachers");

hr = Connector->BeginMessage();

hr = Serializer.CreateInstance(__uuidof(SoapSerializer30));

hr = Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));

hr = Serializer->StartEnvelope(_T("soap"),_T("NONE"),_T(""));

hr = Serializer->StartBody(_T(""));

hr = Serializer->StartElement(_T("FindMusicTeachers"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->StartElement(_T("ZipCode"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(ZipCode);

hr = Serializer->EndElement();

hr = Serializer->StartElement(_T("Instrument"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(_T("0"));

hr = Serializer->EndElement();

hr = Serializer->StartElement(_T("SkillLevel"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(_T("0"));

hr = Serializer->EndElement();

hr = Serializer->StartElement(_T("Style"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(_T("0"));

hr = Serializer->EndElement();

hr = Serializer->StartElement(_T("Radius"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(_T("10"));

hr = Serializer->EndElement();

hr = Serializer->StartElement(_T("RestrictResultsCount"),

_T("http://www.PerfectXML.com/NETWebSvcs/MusicTeachers/"),

_T("NONE"),_T(""));

hr = Serializer->WriteString(_T("5"));

hr = Serializer->EndElement();

hr = Serializer->EndElement();

hr = Serializer->EndBody();

hr = Serializer->EndEnvelope();

hr = Connector->EndMessage();

hr = Reader.CreateInstance(__uuidof(SoapReader30));

hr = Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), _T(""));

CComQIPtr<IXMLDOMDocument2> spResponseXMLDOM;

spResponseXMLDOM = Reader->Dom;

//TODO: Process the response SOAP XML and display the results

//For now, just printing the response XML text as it is.

USES_CONVERSION;

printf(_T("Response: %s\n"), (const char*)W2A(spResponseXMLDOM->xml));

printf(_T("\n\nPress Enter to continue..."));

getchar();

}

int main(int argc, char* argv[])

{

CoInitialize(NULL);

if(argc < 2)

{//insufficient parameters

printf(_T("\nSOAPToolkitLowLevel.exe: Sample Web Service client to find out "

" music teachers within 10-mile radius of a valid given U.S. zipcode\n"));

printf(_T("\nUsage:\tSOAPToolkitLowLevel.exe <US_Zipcode>\n"

"Examples:\n\tSOAPToolkitLowLevel.exe 98007\n\t"

"SOAPToolkitLowLevel.exe 60195"));

printf(_T("\n\nPress Enter to continue..."));

getchar();

return -1;

}

CallWebService(_bstr_t(argv[1]));

CoUninitialize();

return 0;

}

Output:

We do not make use of the header file in this sample application. The sample source code CPP file above, imports the MSXML and SOAP Toolkit type libraries. The supporting function CallWebService (which is called from the main function), creates instances of SoapSerializer, HttpConnector, and SoapReader classes. The HttpConnector instance is initialized by setting the EndPointURL and the SoapAction properties, and the Connect method is used to initialize the HttpConnector instance by using the WSDL.

Note how the SoapSerializer class is used to precisely create the SOAP request message. This class provides the full control over how the message should look like, by allowing us to specify the namespace value, namespaces prefixes to use, encoding style, and other structural details of the SOAP envelope. The SoapSerializer Init method is used above to associate the request envelope with the transport input stream. When the SOAP request envelope is fully created using the SoapSerializer members, the HttpConnector EndMessage method is called to indicate that the request envelope is ready, and to actually post the SOAP message and receive the response, synchronously.

The HttpConnector OutputStream is used to load the response message into the the SoapReader object. In this particular example, we just access the Dom property on the Reader, to load the response SOAP envelope into a MSXML DOMDocument object. You may parse and process this DOMDocument object to get the individual result values. For brevity, we just print the response XML text as it is in the above example.

5. Using PocketSOAP v1.4.1 PocketSOAP is a COM component that can be used to invoke Web Services. The following sample C++ application uses PocketSOAP v1.4.1 COM component to invoke SalesRankNPrice sample Web Service, to find out the Amazon.com sales rank and the price for any given ISBN value.

The source code file (PocketSOAP1.cpp):

#include "stdafx.h"

#include "atlbase.h"

#import "C:\Program Files\SimonFell\PocketSOAP\pSOAP32.dll" named_guids

using namespace PocketSOAP;

void CallWebService(_bstr_t bstrISBN)

{

CComPtr <ISOAPEnvelope> spEnvelope;

HRESULT hr = spEnvelope.CoCreateInstance(CLSID_CoEnvelope);

spEnvelope->SetMethod(_T("GetAmazonSalesRankNPrice"),

_T("http://www.PerfectXML.com/NETWebSvcs/BookService"));

spEnvelope->Parameters->Create(_T("ISBN"),

bstrISBN,

_T("http://www.PerfectXML.com/NETWebSvcs/BookService"),

_T(""), _T(""));

CComPtr <IHTTPTransportAdv> spHTTPTransport;

hr = spHTTPTransport.CoCreateInstance(CLSID_HTTPTransport);

spHTTPTransport->SOAPAction =

L"http://www.PerfectXML.com/NETWebSvcs/BookService/GetAmazonSalesRankNPrice";

_bstr_t bstrEnvelope = spEnvelope->Serialize();

hr = spHTTPTransport->Send(

_T("http://www.perfectxml.net/WebServices/SalesRankNPrice/BookService.asmx"),

bstrEnvelope);

CComVariant cvTransport(spHTTPTransport);

spEnvelope->Parse(cvTransport, _T(""));

bstrEnvelope = spEnvelope->Serialize();

USES_CONVERSION;

printf(_T("Response:\n%s"), W2A(bstrEnvelope));

printf(_T("\n\nPress Enter to continue..."));

getchar();

}

int main(int argc, char* argv[])

{

if(argc < 2)

{//insufficient parameters

printf(_T("\nPocketSOAP1.exe: Sample Web Service client to find out "

" Amazon.com Sales Rank and Price for a given ISBN.\n"));

printf(_T("\nUsage:\tPocketSOAP1.exe <ISBN>\n"

"Examples:\n\tPocketSOAP1.exe 1861005318\n\t"

"PocketSOAP1.exe 0735712867"));

printf(_T("\n\nPress Enter to continue..."));

getchar();

return -1;

}

HRESULT hr = CoInitialize(NULL);

CallWebService(_bstr_t(argv[1]));

CoUninitialize();

return 0;

}

Output:

The above C++ code begins by importing the PocketSOAP type library, and then includes the supporting function CallWebService definition. This function uses the ISOAPEnvelope interface methods to initialize the SOAP request message (by defining the Web Service method to call, namespace to use, and defining the parameters). Next, it uses the IHTTPTransportAdv interface methods to set the SOAPAction, and to actually post the SOAP request. The resultant message is parsed and loaded into the ISOAPEnvelope object, which is then serialized as a string and written out to the console.

Summary

The goal of this article was to show you some of the ways in which you can build Web Services client applications, specifically using Visual C++. The first example illustrated using MSXML XMLHTTP for this purpose; next application used ServerXMLHTTP to invoke a Web Service; third sample application used Microsoft SOAP Toolkit high-level API, while the fourth application presented the code that used Microsoft SOAP Toolkit low-level API. Final, and fifth application, illustrated using PocketSOAP COM library to call a Web Service method.

Download:

CPPSOAP.zip (353 KB ZIP file)

Related Links:

PerfectXML MSXML Focus Section

Visual Basic Developer's Guide to SOAP

Microsoft & Web Services (SOAP)

SOAP Toolkit 3.0

C++ Web services client using Systinet WASP Server for C++

Simplified SOAP Development with SOAP::Lite - Part I

About the author:

Darshan Singh is the founder of PerfectXML.com, the XML community Web site. As an author, he has co-authored various books published by Wrox Press and has written various articles for PerfectXML.com, and other technical sites such as ASPToday and MSDN. Darshan can be reached at darshan@PerfectXML.com.

Get our Newsletter:

E-mail address:

Recent Newsletter

Discount Subscription Offer

10% Discount + Two FREE Issues of Web Services Journal

10% Discount + Two FREE Issues of XML-Journal

Featured Vendors

PerfectXML.com is a proud winner of

Best Educational Web Site (Finalist)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有