C++调用gSoap编写的WEBSERVICE与C#.NET间接口自定义结构体不能重复使用

来源:互联网 发布:python 技术指标 编辑:程序博客网 时间:2024/04/30 13:08

最近项目开发从C/S架构转成B/S架构后,开始使用webservice技术,由于我们的webservice是由vc++实现的,因此用到了gSoap库实现webservice,而上端业务我们采用了C#编写.NET业务逻辑,就牵涉到了很多C#与VC间对接的问题。自定义结构体问题就是我遇到的问题之一:

由于gSoap接口只能最后一个参数作为返回值,那么当我需要返回多个参数时,就需要用到自定义的结构体类型。这里注意gSoap转换时会将结构体的第一个成员作为C#调用时结构的方法返回值,第二个成员则作为方法的最后一个参数返回。

假设现在我编写这样一个VC的接口文件Interface.h:

//gsoap ns service name: Interface//gsoap ns service namespace: http://localhost/Interface.wsdl//gsoap ns service location: http://localhost//gsoap ns service executable: Interface.cgi//gsoap ns service encoding: encoded//gsoap ns schema namespace: urn:serFuncint ns__serFunc(int i,char *res);struct ns__stuErrorResultResponse{int code;char *str;};int ns__ser_USCOREtest(int i, struct ns__stuErrorResultResponse *res);
从代码中我们可以看到我声明了两个接口,第一个结构是最简单最常用的方法serFunc,这个方法命名空间是ns,入参是整型值i,回参是字符串res。第二个是为了实现多参数返回编写的采用自定义结构体参数的方法ser_test,注意USCORE只是gSoap固定的转义,表示前面的下划线转化时禁止转成横杠,这个方法命名空间也是ns,入参是整型值i,回参是结构体的成员code和str,code是错误码,str是错误信息字符串。

以上结构体定义中要注意下,自定义结构体也需要指定命名空间,因此我在结构体名称命名是也加上了ns__来指定命名空间。

首先我是通过

soapcpp2 Interface.h
命令将该接口文件转成WSDL文件和gSoap的cpp和h文件提供给VC程序调用实现WEBSERVICE技术。

那么和C#.NET对接时,要如何实现呢?两种方法,方法一是将WSDL文件直接给C#.NET程序猿,这种方法由于gSoap的wsdl文件内部格式不是很符合要求,C#.NET程序猿需要做一些修改才能使用,我选择了方法二,就是先通过VC命令提示窗口提供的wsdl命令将wsdl文件转成cs文件然后再提供给C#.NET程序猿,这样就可以直接使用了。转换命令是:

wsdl /out:Interface.cs Interface.wsdl
这样我们就可以看到C#.NET程序猿拿到的接口是

int ser_test(int i, out string str)
看接口我们就知道了,ser_test是方法名,其方法返回值int型就是C++端定义的code错误码,i是入参,str是字符串回参,这里因为C#是没有指针概念的,所以转换中将char *转成了string。

以上这个是没有什么疑问的,也比较简单。那么问题就来了,假设下载我有另外一个接口,也需要返回同样参数,就是同时返回错误码和错误信息,我们该怎么去定义呢?

C++程序猿可能会不假思索的按下述方式去做:

int ns__ser_USCOREanother(int i, struct ns__stuErrorResultResponse *res);
然后很直观的就认为提供给C#程序猿的接口是

int ser_another(int i, out string str)

了。实际上,我在开发中遇到了这样的问题,我编写了c++的gsoap客户端测试我提供的接口,程序没有问题也正常使用,但是提供给C#程序猿后没问题就来了,C#程序猿根本就没法使用,会提示ser_another方法无法反射,这是怎么回事呢?检查发现C#那端错误原因是找不到stuErrorResultResponse。为什么呢?我的理解是可能因为ns__stuErrorResultResponse 转换过程中已经被解释,当ns__ser_USCOREanother转换时就不会再被解释,那么ser_another中就找不到stuErrorResultResponse。因此我的解决方法是,ser_another的自定义结构体重新定义一个不同名称的:

//gsoap ns service name: Interface//gsoap ns service namespace: http://localhost/Interface.wsdl//gsoap ns service location: http://localhost//gsoap ns service executable: Interface.cgi//gsoap ns service encoding: encoded//gsoap ns schema namespace: urn:serFuncint ns__serFunc(int i,char *res);struct ns__stuErrorResultResponse{int code;char *str;};int ns__ser_USCOREtest(int i, struct ns__stuErrorResultResponse *res);struct ns__stuAnotherErrorResultResponse{int code;char *str;};int ns__ser_USCOREanother(int i, struct ns__stuAnotherErrorResultResponse *res);

这样一来确实C#程序猿就成功调用了VC提供的接口。我不清楚产生这个问题的真正原因是什么,是不是我所认为的,也不清楚我的方案是否正确?望高手指点。不过我这样处理后确实解决了项目中接口对接的实际问题,这里提供给大家参考。

0 0