Web Service Client tool Evaluation

In the MFC/C++ environment, there are several libraries/tools can be used to integrate with Java Web Service. They are ATL Server, Windows Web Service API and gSoap.

1, ATL Server

ATL Server is C++ Template based technology in Vistual Studio environment.It provides an utility tool to generate proxy code for Web Service client. From Visual Studio 2008, Mirosoft open sourced it, and its official Web site is http://atlserver.codeplex.com. We can download the ATL_Server_Source_and_Headers_9_0_70425_Alpha.zip.  After unzipping this file,  we can find a  solution file under the source sub folder for this tool. It is in the VS 2005 version, which need converted into  VS 2008 version once we double click it to open it. Open the solution file, add the ATL Server include folder in the property

 Then build this sproxy.sln , we can get the sproxy.exe utility.

In Microsoft MSDN, We can find some useful link about how to use the sproxy.exe.

  sproxy [ options ] [ /out:outputfile ] input_location

 

The input_location can be a local WSDL file or  HTTP link for a WSDL.

For example:

 

sproxy /wsdl http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?WSDL

 

will generate a header file  WeatherWS.h.We can add this file in our Web Service Client project to access like:

 

#include "WeatherWS.h"

using namespace WeatherWS;

 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

    CoInitialize(NULL);

    HRESULT hr = S_OK;

    CWeatherWST<CSoapSocketClientT<>> * m_srv = new CWeatherWST<CSoapSocketClientT<>>;

    CComBSTR cityCode = "";

    CComBSTR userId = "";

    CComBSTR * bstrOut;

    int size;

    hr = m_srv->getWeather(cityCode, userId, (BSTR * *)&bstrOut, &size);

    if(FAILED(hr))

    {

    }

    else

    {

            std::cout << bstrOut->m_str << std::endl;

    }

    if (m_srv != NULL)

        delete m_srv;

    CoUninitialize();

      return 0;

}

 

This snippet of code can run successfully.

But when we generate some other Web Service WSDL file, the generated file will cause runtime exception. We created the Web Service – User Detail to get available application for specific user. The WSDL content for this Web Service is listed following:

 

 

<?xml version="1.0" encoding="UTF-8" ?>

- <wsdl:definitions name="UserDetailServiceImplService" targetNamespace="http://security.ipns.enterprise.argushealth.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://security.ipns.enterprise.argushealth.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

- <wsdl:types>

- <xs:schema elementFormDefault="unqualified" targetNamespace="http://security.ipns.enterprise.argushealth.com/" version="1.0" xmlns:tns="http://security.ipns.enterprise.argushealth.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="getAvailableApplications" type="tns:getAvailableApplications" />

  <xs:element name="getAvailableApplicationsResponse" type="tns:getAvailableApplicationsResponse" />

- <xs:complexType name="getAvailableApplications">

- <xs:sequence>

  <xs:element minOccurs="0" name="arg0" type="xs:string" />

  </xs:sequence>

  </xs:complexType>

- <xs:complexType name="getAvailableApplicationsResponse">

- <xs:sequence>

  <xs:element maxOccurs="unbounded" minOccurs="0" name="return" type="tns:application" />

  </xs:sequence>

  </xs:complexType>

- <xs:complexType name="application">

- <xs:sequence>

  <xs:element minOccurs="0" name="name" type="xs:string" />

  <xs:element minOccurs="0" name="url" type="xs:string" />

  </xs:sequence>

  </xs:complexType>

  </xs:schema>

  </wsdl:types>

- <wsdl:message name="getAvailableApplications">

  <wsdl:part element="tns:getAvailableApplications" name="parameters" />

  </wsdl:message>

- <wsdl:message name="getAvailableApplicationsResponse">

  <wsdl:part element="tns:getAvailableApplicationsResponse" name="parameters" />

  </wsdl:message>

- <wsdl:portType name="UserDetailService">

- <wsdl:operation name="getAvailableApplications">

  <wsdl:input message="tns:getAvailableApplications" name="getAvailableApplications" />

  <wsdl:output message="tns:getAvailableApplicationsResponse" name="getAvailableApplicationsResponse" />

  </wsdl:operation>

  </wsdl:portType>

- <wsdl:binding name="UserDetailServiceImplServiceSoapBinding" type="tns:UserDetailService">

  <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />

- <wsdl:operation name="getAvailableApplications">

  <soap:operation soapAction="" style="document" />

- <wsdl:input name="getAvailableApplications">

  <soap:body use="literal" />

  </wsdl:input>

- <wsdl:output name="getAvailableApplicationsResponse">

  <soap:body use="literal" />

  </wsdl:output>

  </wsdl:operation>

  </wsdl:binding>

- <wsdl:service name="UserDetailServiceImplService">

- <wsdl:port binding="tns:UserDetailServiceImplServiceSoapBinding" name="UserDetailServiceImplPort">

  <soap:address location="http://172.16.23.25:9081/user-application-ws/UserDetail" />

  </wsdl:port>

  </wsdl:service>

  </wsdl:definitions>

 

 

After running

sproxy /wsdl http://172.16.23.25:9081/user-application-ws/UserDetail?wsdl

We add the generated file UserDetailServiceImplService.h to RSOClient project, use the following snippet of code to access the Web Service:

 

 

#include "UserDetailServiceImplService.h"

using namespace UserDetailServiceImplService;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

      CoInitialize(NULL);

    HRESULT hr = S_OK;

    CUserDetailServiceImplServiceT<CSoapSocketClientT<>> * m_srv = new CUserDetailServiceImplServiceT<CSoapSocketClientT<>>;

    CComBSTR userId = "charles";

    CComBSTR * bstrOut;

    int size;

      getAvailableApplications arg;

      application AvailableApplicationsResponse;

      application* p = &AvailableApplicationsResponse;

      application** ppAvailableApplicationsResponse = &p;

      arg.arg0 = L"charles";

      hr = m_srv->_getAvailableApplications(arg,    ppAvailableApplicationsResponse, &size);

    if(FAILED(hr))

    {

            std::cout<< L"fail" << std::endl;

    }

    else

    {

        for (int i = 0; i < size; i++)

        {

      std::cout << ppAvailableApplicationsResponse[i]->name << std::endl;

      std::cout << ppAvailableApplicationsResponse[i]->url << std::endl;

        }

    }

    if (m_srv != NULL)

        delete m_srv;

    CoUninitialize();

}

 

 

hr = m_srv->_getAvailableApplications(arg,    ppAvailableApplicationsResponse, &size);

Always goes to

    if(FAILED(hr))

    {

            std::cout<< L"fail" << std::endl;

    }

 

After carefully debugging we found that the generated proxy is sending incorrect SOAP content. From the captured the network package, we can see

 

There are one more <getAvailableApplications> sub element under <getAvailableApplications>. But from the WSDL file, the getAvailableApplications element should be

The element arg0 is the direct child element of getAvailableApplications. When we evaluated the gSOAP, we found that gSOAP generates the correct format.

 

2, Windows Web Service API

 WWSAPI is a native-code implementation of SOAP which provides core network communication functionality by supporting a set of the WS-* and .NET-* family of protocols. WWSAPI is designed to be used by components/applications which fall into one of the following categories:

 

  • Native code mandate
  • Require minimal dependencies
  • Require minimal startup time
  • Memory constrained environments

Windows Web Services API (WWSAPI) is an operating-system component of the following operating systems:

 

  • Windows 7
  • Windows Server 2008 R2
  • XP   SP3
  • Vista

Windows Web Services API  sounds like a perfect option for us, all the original download link are not available now. It needs us send formal business email to Microsoft  to get redistributable installers.   We mainly referenced to  this official blog  of MSDN . http://blogs.msdn.com/b/windowssdk/archive/2009/10/20/building-web-services-on-windows-with-c.aspx

 

3, gSOAP

   The official web site for gSOAP is   http://sourceforge.net/projects/gsoap2. From there we can learn that:

 The gSOAP toolkit is a portable C and C++ software development toolkit for XML Web services and generic XML data bindings. Easy-to-use XML auto-serialization allows you to directly integrate C and C++ data with XML. Includes WSDL/XSD schema binding and auto-coding tools, stub/skeleton compiler, Web servers (with SSL), integrated XML processing with schema validation, fast MIME/MTOM streaming, SOAP and REST, WS-* protocols (WS-Security, WS-Policy, etc), XML-RPC and JSON serialization.

 

 Currently the stable version is 2.8.8.After download  and unzip  the gsoap_2.8.8.zip file, we can find there are two binary tools  under the sub folder gsoap/bin/win32:

      wsdl2h.exe   

      soapcpp2.exe

There is also source code for them under the src folder. Of course we can build  both of them from scratch. There is VisualStudio2005 folder, under which the Readme is very importance.  Follow  the Readme, we can also build the two tools by ourselves .

 

 

 The two tools has some function as  sproxy.exe in ATL Server.  The difference is we need do it with two steps. First we use wsdl2h to generate a header file , then use soapcpp2 to generate the files we need use in our project base on this header file. For example:

       1, wsdl2h -o  userservice.h -n namespacename  URL or file name

          the generatd userservice.h file will be used in the next step. 

       2, soapcpp2  userservice.h -C -i -x -I F:\study_code\mfc\gsoap_2.8.8\gsoap-2.8\gsoap\import

                  

            F:\study_code\mfc\gsoap_2.8.8\gsoap-2.8\gsoap\import  is the import folder under the gsoap.

        soapcpp2 will generate totally fix files:

 

  •   soaph.h
  •  soapc.cpp
  •   soapStub.h
  •  soapUserDetailServiceImplServiceSoapBindingProxy.cpp
  •  soapUserDetailServiceImplServiceSoapBindingProxy.h
  • UserDetailServiceImplServiceSoapBinding.nsmap

 

After generating the files , we need use the files in our Web Service client project. Except the generated files, we also need other two files :   stdsoap2.h, stdsoap2.cpp ( they are under the gSoap folder).   We can use the following snippet of code :

 

#include "UserDetailServiceImplServiceSoapBinding.nsmap"

#include "soapUserDetailServiceImplServiceSoapBindingProxy.h"

const char endpoint[] = "http://172.16.23.25:9081/user-application-ws/UserDetail";

 

CReEngiApps GetApps(const char* userId)

{

      CReEngiApps  apps;

 

      UserDetailServiceImplServiceSoapBindingProxy  proxy(SOAP_XML_INDENT);

      rso1__getAvailableApplications rso1__getAvailableApplications_;

      rso1__getAvailableApplicationsResponse rso1__getAvailableApplicationsResponse_;

 

      std::string user = userId;

      rso1__getAvailableApplications_.arg0 = & user;

      int ret = proxy.getAvailableApplications(endpoint, NULL, &rso1__getAvailableApplications_,  &rso1__getAvailableApplicationsResponse_);

      if (ret == SOAP_OK)

      {

            std::vector<rso1__application * > & applications = rso1__getAvailableApplicationsResponse_.return_;

            apps.m_appNum = applications.size();

            for (int i=0; i < apps.m_appNum; i++)

            {

                  memcpy(apps.m_apps[i].m_szAppName, applications[i]->name->c_str(), strlen(applications[i]->name->c_str()));

                  memcpy(apps.m_apps[i].m_szAppUrl, applications[i]->url->c_str(), strlen(applications[i]->url->c_str()));

            }

      } else

      {

            apps.m_appNum = 0;

      }

      return apps;

}

 

ATL Server VS gSOAP

    1, ATL Server is C++ template based.Its generated code has lots of template code. Template code is much harder than normal code to understand.gSOAP generates simple code, event only C code.

2, ATL Server has a fatal issue, we found, it generates incorrect SOAP content, which can cause request failed. So far, the code generated by gSOAP is good, no big issue.

 

Conclution

   gSOAP is an open source tool can generate portable C/C++ Web Service proxy code.The generated code is easy to use.

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自bruce008.iteye.com/blog/1498180