在C++中使用soap toolkit访问Web Service(转)
在C++中使用soap toolkit访问Web Service,一般要用到以下几个接口:
Connector->Property["SoapAction"] = "http://tempuri.org/LoginTest"
- ISoapConnector
- ISoapSerializer
- ISoapReader
这三个接口顾名思义。ISoapConnector实现了在对象之间发送和接收SOAP消息的传输协议;ISoapSerializer用于序列化(串行化),创建、封装SOAP消息;ISoapReader用于读取SOAP消息,将SOAP消息解析为一个DOM模型,并提供了一系列操作该DOM模型的方法。
使用Soap Toolkit的应用程序,需要引入动态库MSSOAP1.dll(当前最新版本是Soap Toolkit3.0:MSSOAP3.dl),同时还需要msxml3.dll用于解析DOM和XML。在程序的开头可以这样来引入相关的文库和名称空间:
#import "msxml3.dll"
using namespace MSXML2;
using namespace MSXML2;
#import "D:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll" \
exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", "_ULARGE_INTEGER",
exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", "_ULARGE_INTEGER",
"tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib;
using namespace MSSOAPLib;
废话少说,觉得还是来分析一段示例代码比较实在。 假设在Web服务器上(如http://localhost/MyTestWebService/),有一个名为Loginout的Web服务,并提供了一个Web Mothod,原型如下:
string LoginTest(string strIP, int nPort);
下面的代码说明了如何来访问该Web服务。
ISoapConnectorPtr Connector;
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapReaderPtr Reader;
// 与Web服务连接
Connector.CreateInstance(__uuidof(HttpConnector));
Connector->Property[L"EndPointURL"] =
Connector.CreateInstance(__uuidof(HttpConnector));
Connector->Property[L"EndPointURL"] =
_variant_t( "http://localhost/MyTestWebService/Loginout.asmx");
HRESULT result = Connector->Connect();
HRESULT result = Connector->Connect();
// 创建SoapSerializer对象
Serializer.CreateInstance(__uuidof(SoapSerializer));
Serializer.CreateInstance(__uuidof(SoapSerializer));
// 将serializer连接到connector的输入字符串
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
Connector->Property["SoapAction"] = "http://tempuri.org/LoginTest"
// 开始soap消息
Connector>BeginMessage();
Connector>BeginMessage();
// 创建SOAP消息
Serializer->startEnvelope("","","");
Serializer->startBody("");
Serializer->startElement("LoginTest","http://tempuri.org/","","");
Serializer->startElement("strIP","http://tempuri.org/","","");
Serializer->writeString("192.168.1.170");
Serializer->endElement();
Serializer->startEnvelope("","","");
Serializer->startBody("");
Serializer->startElement("LoginTest","http://tempuri.org/","","");
Serializer->startElement("strIP","http://tempuri.org/","","");
Serializer->writeString("192.168.1.170");
Serializer->endElement();
Serializer->startElement("nPort","http://tempuri.org/","","");
Serializer->writeString("8000");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
Serializer->writeString("8000");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
// 将该soap消息发送给web服务
Connector->EndMessage();
Connector->EndMessage();
// 读取响应soap消息
Reader.CreateInstance(__uuidof(SoapReader));
Reader.CreateInstance(__uuidof(SoapReader));
// 将reader联接到connector的输出字符串
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");
DWORD dwRt = GetLastError();
// 显示结果
printf("Soap return result: %s \n",(const char *)Reader->RPCResult->text);
CoUninitialize();
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");
DWORD dwRt = GetLastError();
// 显示结果
printf("Soap return result: %s \n",(const char *)Reader->RPCResult->text);
CoUninitialize();
上面程序将打印出Web服务的返回值。
几点说明:
- http://localhost/MyTestWebService/Loginout.asmx 是提供Web服务的URL。
- "http://tempuri.org/"是Web服务所属的名称空间(如果Web服务提供者没有指定名称空间,将会使用该默认名称空间)。
- 设置Property时的SoapAction就是要调用的WebMethod“http://tempuri.org/LoginTest"。我觉得称作SoapOperation似乎更好理解些。
- Reader->RPCResult->text是调用WebMethod的string类型返回值。如果要读取返回的参数或复杂对象,可以使用ISoapReader的相关方法。
- 另外,按上述方法,如果相关参数中含有中文,service服务器接收到的相应内容可能会是乱码!例如我做demo时server端是基于.NET的,字符串肯定是Unicode,以两个字节表示;而soap toolkit默认的xml编码规则是UTF-8(使用该编码,虽然也称为Unicode,但是汉字会被编码为2到3个字节不等),这就产生了冲突。解决的办法是soap调用startEnvelope()时第三个参数指定encoding:UTF-16,这样所有字符均是以2个字节编码。