|
Summary
|
 |
MSXML provides a class called XMLHTTP that is a high-level wrapper around WinInet library.
This class implements IXMLHTTPRequest interface and allows sending
GET and POST requests over HTTP. We can send and receive any data (not just XML) over HTTP
using this class.
Today we'll learn how to use XMLHTTP to send a POST request to a remote server from the client.
We'll POST a SOAP request package to the Temperature Web service
to get the current temperature given the ZipCode.
This application accepts ZipCode as a command line parameter,
if provided, else defaults to value of gszDefZipCode global
variable; creates a SOAP request package and POSTs that to the
Web service using XMLHTTP. The current temprature is
retreived from the SOAP response package using DOM.
|
|
Steps
|
 |
Steps that we followed to create this application:
|
1.
|
Start Visual C++ 6.0 and create a new Win32 Console Application project.
|
|
2.
|
Add the following lines in the stdafx.h:
#include <TCHAR.H>
#include <stdio.h>
#include <time.h>
#import "msxml4.dll"
// ^^^^^^^^^^^
// If this import statement fails, you need to install MSXML 4.0 SP1 from:
//
// http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/766/msdncompositedoc.xml
#include <msxml2.h>
// ^^^^^^^^^^
// If this include statement fails, you need to install MSXML 4.0 SP1 SDK from:
//
// http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/766/msdncompositedoc.xml
//
// You also need to add the include file and library search path
// to Visual C++'s list of directories (Tools > Options... > Directories).
using namespace MSXML2;
inline void EVAL_HR( HRESULT _hr )
{ if FAILED(_hr) throw(_hr); }
|
|
3.
|
The above lines import the MSXML 4 type library and
defines a tiny utility function to check the HRESULT value.
|
|
4.
|
Next, we create a header file (GlobalDefs.h) and define some global variables.
// Globals
LPCTSTR gszPOSTURL = _T("http://services.xmethods.net:80/soap/servlet/rpcrouter");
LPCTSTR gszPkgSOAP =
_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'></zipcode> "
" </ns1:getTemp> "
" </SOAP-ENV:Body> "
" </SOAP-ENV:Envelope>"
);
LPCTSTR gszDefZipCode = _T("60195");
#define TEMP_SIZE _MAX_PATH // size of short buffer
static _TCHAR szTemp[TEMP_SIZE]; // multipurpose buffer on stack
static DWORD dwLen; // buffer size
|
|
5.
|
In the above lines we define the URL (gszPOSTURL) where we'll POST the SOAP request and the SOAP request XML (gszPkgSOAP) text.
Note that in the SOAP request XML above, the value of zipcode element is empty. We'll use DOM in the code
to load this XML text and set the value of zipcode element using either the command line parameter
or the default value.
|
|
6.
|
Here is how the main function looks like:
#include "GlobalDefs.h"
#include "Utils.h"
int main(int argc, char* argv[])
{
try
{
EVAL_HR(CoInitialize(NULL));
// Make sure that MSXML 4.0 is installed
if (!isMSXMLInstalled())
return -1;
_bstr_t strZipCode;
// if ZipCode command-line parameter not passed
if (argc < 2)
strZipCode = gszDefZipCode;
else
strZipCode = argv[1];
float fTemp = -1;
// Utility function that sends a SOAP POST to
// a Web service using MSXML XMLHTTP
getZipCodeTemp(strZipCode, &fTemp);
if (fTemp > 0)
{
printf("\nCurrent temprature at %s zipcode area is %.2f.\n",
(LPCSTR)strZipCode, fTemp);
}
else
{
printf("An error occurred.");
}
}
catch(...)
{//exception handling
}
_ftprintf(stdout, "\n\nPress Enter to continue...");
getchar();
CoUninitialize();
return 0;
}
|
|
7.
|
The main function starts with a utility function to make sure MSXML is installed. See past sample
applications or download the code for this sample for more details on isMSXMLInstalled utility function.
We then set the strZipCode from the command line parameter (if passed) or from the global variable (default value).
Next, we call another utility function getZipCodeTemp which accepts the ZipCode (first parameter), sends the POST request and
returns the current temprature as a floating point number (second parameter).
|
|
8.
|
Here is how getZipCodeTemp function looks like:
void getZipCodeTemp(const _bstr_t &strZipCode, float* fTemp)
{
try
{
// Step 1: Load the SOAP message XML using gszPkgSOAP global variable
IXMLDOMDocument2Ptr pXMLDoc = NULL;
EVAL_HR(pXMLDoc.CreateInstance("Msxml2.DOMDocument.4.0"));
// Load the document synchronously
pXMLDoc->async = false;
// Load the XML document
pXMLDoc->loadXML(gszPkgSOAP);
// Step 2: Update the zipcode node in the SOAP XML message
// Assuming "zipcode" node will always be there
// skipping the step to check if it exists
pXMLDoc->selectSingleNode("//zipcode")->nodeTypedValue = strZipCode;
// Step 3: Create XMLHTTP and send a POST request to the Web service
IXMLHTTPRequestPtr pXH = NULL;
EVAL_HR (pXH.CreateInstance("Msxml2.XMLHTTP.4.0"));
EVAL_HR (pXH->open("POST", gszPOSTURL,
_variant_t(VARIANT_FALSE), _variant_t(""), _variant_t("")));
EVAL_HR (pXH->setRequestHeader("Content-Type", "text/xml"));
EVAL_HR (pXH->send(pXMLDoc->xml));
// Step 4: If we got back the success response back
// get the value of "return" node from the response SOAP
// message
if (pXH->status == 200)
{// Success
pXMLDoc = pXH->responseXML;
// Assuming "return" node will always be there
// skipping the step to check if it exists
_bstr_t strTemp = pXMLDoc->selectSingleNode("//return")->nodeTypedValue;
*fTemp = (float)atof(strTemp);
}
else
{
*fTemp = (float)-1;
}
}
catch(...)
{// Exception handling
}
}
|
|
9.
|
As mentioned earlier, we first load the SOAP request XML text (gszPkgSOAP) using MSXML DOM and
update the value of zipcode node using selectSingleNode method and nodeTypedValue property.
We then create an instance of XMLHTTP object, and call open, setRequestHeader, and send methods on it.
If the POST was successful (status == 200), the response SOAP XML would be available in the
XMLHTTP's responseXML property. We use this property to get to the return node in the
response SOAP package, convert this string to float and return it to the main function.
|
|
|
Here is the text from the Readme.txt file included with the code download.
Sample Application to illustrate using MSXML 4.0 XMLHTTP class
(IXMLHTTPRequest interface) to send a HTTP request.
The XMLHTTP class uses the WinInet library and supports sending
requests over HTTP. The standard HTTP operations (GET and POST)
are supported. Supports Synchronous and Asynchronous HTTP access.
In this application, we'll use MSXML DOM and XMLHTTP to POST
a SOAP request to a Web service and process the response. The
Web service we'll be using in this application returns the
current temprature given the Zipcode.
This application accepts ZipCode as a command line parameter,
if provided, else defaults to value of gszDefZipCode global
variable; creates a SOAP request package and POSTs that to the
Web service using XMLHTTP. The current temprature is
retreived from the SOAP response package using DOM.
More details on the Temprature Web service can be found at
http://www.xmethods.com/ve2/ViewListing.po?serviceid=8.
--------------------------------------------------------------
Copyright (C) 2002 http://www.perfectxml.com
Created: Thursday, July 18, 2002
Author: perfectxml.com Team (msxml@perfectxml.com)
--------------------------------------------------------------
|
|
|
More Information
|
 |
|
|
|