公司业务需要,用到Soap同WebService对接。本来想使用MS soap toolkit,但是这东东用到的系统的XML解析库,在不同的windows平台下存在冲突,虽然能规避解决,但觉得不完美,转用gsoap
![微笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
1、资料
下载地址
http://sourceforge.net/projects/gsoap2/
官网
http://genivia.com/Products/gsoap/index.html
官方学习教程
http://genivia.com/Products/gsoap/documentation.html
2、使用VS2010创建简单WebService
2.1 创建工程
New project --> Visual C# --> ASP.Net Empty Web Application
2.2 添加WebServices
Add New Item --> Web Service
2.3 WebService代码
修改了下原有代码,加法接口
namespace WebApplication_Test
{
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public double TestAdd(double a, double b)
{
return a + b;
}
}
}
2.4 运行结果
http://localhost:12676/WebService1.asmx
作为服务器的链接地址
3 使用Gsoap生成代码
这里使用gsoap_2.8.17版本,最新的请到官网中下载。
用到.\gsoap-2.8\gsoap\bin\win32
wsdl2h.exe 根据WebService生成.h文件,其中描述了soap服务器的接口等,可以通过doxygen来获得头文件信息。
cmd窗口运行命令:
wsdl2h.exe -o head.h http://localhost:12676/WebService1.asmx?WSDL
-o 指定需要输出的头文件,默认为当前目录
head.h 为输出的.h文件
http://localhost:12676/WebService1.asmx?WSDL 为服务器地址+?WSDL
soapcpp2.exe 解析头文件,生成相应的源代码,运行:
soapcpp2.exe -C -i -x head.h -I ../../Import
常用命令
-C 仅生成客户端代码
-S 仅生成服务器端代码
-c 产生纯C代码,否则是C++代码(与头文件有关)
-I 指定import路径,导入../../Import(不导入会失败)
-x 不要产生XML示例文件
-i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。
生成最终文件如下:
其中xxxProxy.h、xxxProxy.cpp即为客户端类代码
对于应用程序,需要使用到的为
soapC.cpp、soapH.h、soapStub.h、soapWebService1SoapProxy.cpp、soapWebService1SoapProxy.h、WebService1Soap.nsmap
以及 ../../stdsoap2.cpp、../../stdsoap2.h
4 生成客户端程序
4.1 简单的创建MFC对话框程序
4.2 添加以上soap文件
由于MFC默认要求CPP文件包含stdafx.h头文件,针对soapC.cpp、soapWebService1SoapProxy.cpp、stdsoap2.cpp,直接编译会提示
1>soap\soapC.cpp(16): warning C4627: '#include "soapH.h"': skipped when looking for precompiled header use
1> Add directive to 'StdAfx.h' or rebuild precompiled header
1>soap\soapC.cpp(2119): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1> soapWebService1SoapProxy.cpp
1>soap\soapWebService1SoapProxy.cpp(11): warning C4627: '#include "soapWebService1SoapProxy.h"': skipped when looking for precompiled header use
1> Add directive to 'StdAfx.h' or rebuild precompiled header
1>soap\soapWebService1SoapProxy.cpp(221): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1> stdsoap2.cpp
1>soap\stdsoap2.cpp(895): warning C4244: 'return' : conversion from 'std::streamsize' to 'size_t', possible loss of data
可手动修改添加头文件,或者修改编译条件
4.3 调用webService
响应OnOK程序,代码如下
#include "soapWebService1SoapProxy.h"
#include "WebService1Soap.nsmap"
void CTestSoapCPlusPlusDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
//CDialogEx::OnOK();
WebService1SoapProxy mySoap;
_ns1__TestAdd stuParam;
stuParam.a = 10.0;
stuParam.b = 100.0;
_ns1__TestAddResponse stuResponse;
//! 调用
char szSever[] = "http://localhost:12676/WebService1.asmx?wsdl";
if (SOAP_OK == mySoap.TestAdd(szSever, NULL, &stuParam, &stuResponse))
{
CString strMsg;
strMsg.Format("result:%.2f", stuResponse.TestAddResult);
MessageBox(strMsg);
}
else
{
CString strMsg;
strMsg.Format("result:%s", mySoap.soap_fault_string());
MessageBox(strMsg);
}
}
注意包含文件
soapWebService1SoapProxy.h,WebService1Soap.nsmap
其中:
szServer指定服务器,如果不明确指定,则使用默认服务器
OK,大功告成
5 碰到的问题
5.1 nafxcw.lib 同 LIBCMT.lib冲突
1> TestSoapDlg.cpp
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z) already defined in libcpmt.lib(newaop.obj)
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) already defined in LIBCMT.lib(delete2.obj)
1>J:\C++\Soap\gSoap\Program\TestSoap\Release\TestSoap.exe : fatal error LNK1169: one or more multiply defined symbols found
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:06.67
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
原因:
nafxcw是MFC运行链接库libcmt是C运行库,编译器先链接了libcmt,再链接nafxcw,导致符号重复定义,具体参见
http://support.microsoft.com/kb/148652/zh-cn
解决:
将两个库都忽略,再按顺序添加,编译器将根据指定的顺序执行链接
注意:
Debug版本下两个库为 nafxcwd.lib、LIBCMTD.lib
Release版本下两个库为 nafxcw.lib、LIBCMT.lib
不注意可能会出现很坑的错误。。。。
5.2 stdSoapC.cpp 无法解析的外部符号_namespace
原因:
nsmap包含错误,该文件是namespace map,定义了个namespaces变量,在stdSoap.cpp中有
5.3 传输中文时,出现乱码
解决(原因没深入):
初始化WebService1SoapProxy类时,使用构造函数
/// Constructor with engine input+output mode control
WebService1SoapProxy(soap_mode iomode);
设置iomode为
SOAP_C_UTFSTRING
6 相关程序文件
包括websevices、客户端、gsoap文件,见
http://download.csdn.net/detail/otosu/6953421