Unmanaged C++ client for WCF service.

Recently I have been evaluating different options and solutions for creating distributed network applications. Of course, this definition is too broad and there might be hundreds of answers and they all would be useful in different circumstances but I paid special attention to WCF.

As Microsoft released a Visual Studio 2008, I can hardly see any reasons why someone who is up to developing a distributed network application might choose anything different. New Studio even has a project template for WCF services, what makes network servers and clients development as easy as can be… But, of course, that would only work if no other platform except Windows is considered. Which is not uncommon.

So, what options are there if we need to build a client for existing WCF service that would work where .NET framework is not installed (because it is not available for that platform)? There is one way offered by Microsoft (using sproxy.exe) and some could use it. Other way involves writing “moniker” in .NET and then use it via COM. They both would work on windows platform only, moreover, I couldn’t make sproxy.exe to work with WCF service at all, so I had to look for the third option, which was gSOAP. And this worked.

Of course, you’ll need to download and install (and, probably, build before installing) gSoap, what, I hope, will not be a big problem. Then let’s assume we have a WCF service with following service contract running (this is just an example, I can hardly imagine a need in remote string concatenation service):

namespace SimpleServer
{
[ServiceContract]
public interface iStringService {
[OperationContract]
/**
*

* String concatenation *

* */ string Concat(string first, string second); } }

Writing, compiling and hosting the service is out of the scope of this article, however, I need to note that the only binding type I could make to work with gSoap with the service was Basic Http – keep it in mind when hosting your service.
Then is a step where a controversial feature of VS 2008 I have already written about (wcfsvchost.exe) really helps us – we need to get the service hosted and running before start using gSOAP. Run the project and have service hosted.

gSoap comes with two tools that make all stubs and bindings to programming language, which could be either C or C++, however, I was only interested in writing application in C++, which turned to be pretty straightforward.

At first, you’ll need to use wsdl2h.exe and the WCF service I mentioned above hosted and running. Assume that service entry point is http://localhost:8080/MyService/, and service WSDL is available on URL http://localhost:8080/MyService/metadata/?wsdl. This means that service endpoints’ configuration looks like the following:

name=”SimpleServer.Service1″>

binding=”basicHttpBinding” bindingConfiguration=”HttpBase” bindingNamespace=””
contract=”SimpleServer.iSimpleService”>

contract=”IMetadataExchange” />

;

Note – Visual Studio can generate metadata endpoint for you with some URL like “http://localhost:8978/Design_Time_Addresses…”, which can be used as well.

Execute the following:

wsdl2h.exe -o myService.h http://localhost:8080/MyService/metadata/?wsdl

It will create a file myService.h contains some basic bindings enough to write SOAP client in C. As I wanted to use C++, I had to move a little bit further and take a next step:

soapcpp2 -i -I ..\gsoap\import -x -C myService.h

Option -i tells compiler to derive SOAP proxies from soap struct. This is not necessary, but I noticed the code looks less messy this way.
Option -I specifies path to import directory in gSOAP distribution.
Option -C enables client-side code generation only
and -x is needed if you don’t need to have any sample XML message files.

This will generate proxies for all service’s binding types that were configured, but we are only interested in ones that start with “soapBasicHttpBinding_” (in my case, the full file names were soapBasicHttpBinding_USCOREiStringServiceProxy.h and soapBasicHttpBinding_USCOREiStringServiceProxy.cpp) because others do not usually work (I failed with net.tcp and did not try wsHttpbinding at all).

Now let’s use this proxy:

#include “soapBasicHttpBinding_USCOREiStringServiceProxy.h”
#include “soapBasicHttpBinding_USCOREiStringServiceProxy.h”
#include “BasicHttpBinding_USCOREiStringService.nsmap”
#include

int main(int argc, _TCHAR* argv[])
{
BasicHttpBinding_USCOREiStringServiceProxy MyProxy;
/* Uncomment two following strings and modify path to the
service according to your network configuration */
// static const char* const pszEndPoint=”http://localhost:8080/MyService/”;
// MyProxy.soap_endpoint=pszEndPoint;
std::string s1(“First string”);
std::string s2(“Second string”);
// Note this:
_ns1__Concat Param;
_ns1__ConcatResponse Response;
Param.first = &s1;
Param.second = &s2;
if (MyProxy.Concat(&Param,&Response)==SOAP_OK)
{
std::cout
<< "Service responded: " << (*Response.ConcatResult) ; } else { std::cout << "SOAP service call error" ; } } This still looks a little messy but gives an idea. If you look at BasicHttpBinding_USCOREiStringServiceProxy class implementation, you will see that each method of WCF service has corresponding method in that class, but signature is different. Method Concat has two parameters, first for input values and second for output, what explains what generated _ns1__Concat and _ns1__ConcatResponse structures are used for. That's it - this little example worked. Of course, you'll need to add generated files into your project as well as stdsoap2.cpp (which can be found in main directory of gSOAP) and pay attention to *.nsmap file. Of course, this does not cover all possible questions that may arise, but it gives a good starting point. From my point of view, gSOAP would be a good solution when there is a need to write a client for existing WCF service.

Leave a comment ?

52 Comments.

  1. WCF services development made easy in VS 2008? at blinnov’s blog - pingback on Tuesday January 22nd, 2008 at 03:54 PM
  2. Great article!!!

    I was wondering what are the changes needed to be done on order to have gSoap connect via wsHttpbinding binding? I have tried to modify the example described above with no luck….

    Any help will be appreciated (I need to use wsHttpbinding due to authentication, security etc)

    Thanks

  3. Hi,

    Thanks!

    I’m afraid no gSoap client can work with wsHttpBinding. At least I did not succeed with it too 🙁
    It definitely has something to do with authentication method in wsHttpBinding. gSoap does not seem to support it so far.

  4. Congratulation for the article!

    Can I use gSoap with NetTCPBingind?

  5. Thanks hunsoul,

    Didn’t try that but I suspect it won’t work as gSoap is supposed to work over HTTP, while NetTCPBinding is using (presumably) binary protocol.

  6. Im a beginner programmer. I have only visual studio 2005 and dot net frame work installed on my machine. I have installed the gsoap .rar file. How do i go about the installation of gsoap?

  7. Hi. I tried following your steps and added all the files into my project. However I get the following linker error:

    Linking…
    stdsoap2.obj : error LNK2001: unresolved external symbol _namespaces
    Debug/TestingWebService.exe : fatal error LNK1120: 1 unresolved externals
    Error executing link.exe.

    Can you help me with this?

  8. Hi,

    That indicates that you most likely did not include stdsoap2.cpp into your project.

  9. I tried this once again.

    Added the following generated files to my c++ project

    soapBasicHttpBinding_USCOREIPortfoliosProxy.cpp
    soapBasicHttpBinding_USCOREIPortfoliosProxy.h

    soapC.cpp
    soapH.h

    stdsoap2.cpp
    stdsoap2.h

    soapStub.h

    I also included

    BasicHttpBinding_USCOREIPortfolios.nsmap (tried not including it also)

    When I compile, I get the following linker error:

    Linking…
    stdsoap2.obj : error LNK2001: unresolved external symbol _namespaces
    Debug/TestingWebService.exe : fatal error LNK1120: 1 unresolved externals
    Error executing link.exe.

    I tried creating a c++ project on VC 6.0 as well as VS 2008 but same issues.

    Any help?

  10. Which gSOAP version are you using?

  11. The version I have is gSoap 2.7. Should I be using another version?

  12. Sorry. I actually downloaded gsoap_2.7.12.tar

  13. Hi. Im now able to compile my project successfully.

    however when i call the wcf service method, I get a HTTP 415 error – Unsupported Media type.

    Do you know why I could be getting this error?

    the code snippet is:

    _ns3__ShowPortfolios param;
    _ns3__ShowPortfoliosResponse response;

    int in = 1;
    param.userKey = ∈

    BasicHttpBinding_USCOREIPortfoliosProxy myProxy;
    if(myProxy.ShowPortfolios(&param,&response) == SOAP_OK)
    {
    cout << “here”;
    }

  14. There are good chances your service is not configured to accept Basic HTTP binding. At least when I was playing with it I was getting similar errors.

  15. Hi there once again. I have been working with gSoap for a week now. I am facing an issue in getting data from WCF. There is a service which serializes certain file data into a Stream and returns that to the client.

    The service has certain message header attributes and a message body attribute for the file stream.

    The problem I’m facing is, I’m able to receive the message headers, but when I watch the output variable for the stream data, it is empty.

    Another thing I noticed is that soap->buf does contain some of the data (which means the service is returning some data).

    The proxy classes are so confusing that I can’t figure out where the issue is.

    Please let me know if you can help.

    Thanks,
    Vishal

  16. I can only think that WCF service serializes that stream as a compound data type, which cannot be serialized by gSOAP by itself. Take a look at wsdl to see how stream is send.

  17. You’re right. WCF is serializing the data as a compound data type.

    Here is the class which is used:

    [Serializable]
    class SerializeFileInfo
    {
    public SerializeFileInfo(string name, byte[] buffer)
    {
    fileName = name;
    fileBuffer = buffer;
    }

    string fileName;
    public string FileName
    {
    get
    {
    return fileName;
    }
    }

    byte[] fileBuffer;
    public byte[] FileBuffer
    {
    get
    {
    return fileBuffer;
    }
    }
    }

    This gets serialized into a SYstem.IO.Stream using the BinaryFormatter.

    The client side proxy class for the stream is:

    class SOAP_CMAC xsd__base64Binary
    {
    public:
    unsigned char *__ptr;
    int __size;
    char *id; /* optional element of type xsd:string */
    char *type; /* optional element of type xsd:string */
    char *options; /* optional element of type xsd:string */
    struct soap *soap; /* transient */
    public:
    virtual int soap_type() const { return 15; } /* = unique id SOAP_TYPE_xsd__base64Binary */
    virtual void soap_default(struct soap*);
    virtual void soap_serialize(struct soap*) const;
    virtual int soap_put(struct soap*, const char*, const char*) const;
    virtual int soap_out(struct soap*, const char*, int, const char*) const;
    virtual void *soap_get(struct soap*, const char*, const char*);
    virtual void *soap_in(struct soap*, const char*, const char*);
    xsd__base64Binary() : __ptr(NULL), __size(0), id(NULL), type(NULL), options(NULL), soap(NULL) { }
    virtual ~xsd__base64Binary() { }
    };

    However, all its members are empty.

  18. Here is the message body definition on WCF side:

    [MessageBodyMember(Namespace = Namespaces.DataContractSchemasNamespace, Name = “FileByteStream”,Order=1)]
    public System.IO.Stream FileByteStream { get; set; }

    However, when I browse the WSDL, it just shows:

    I cannot see a mention of FileByteStream anywhere in the WSDL.

    Just to mention this service is working fine when I call it through an ASPX page and it does download the files.

  19. Take a look at official gSoap manual, 18.5. It looks like gSOAP did not generate deserializer for your custom type by some reason.

  20. I am not surprized WSDL does not implicitly contain FileByteStream. I am almowt sure you’ll have to define your own deserializer for that structure in c++ client.

  21. I see the following code generatedby gSoap

    SOAP_FMAC3 int SOAP_FMAC4 soap_out_ns7__StreamBody__(struct soap*, const char*, int, const ns7__StreamBody__ *, const char*);
    SOAP_FMAC3 ns7__StreamBody__ * SOAP_FMAC4 soap_get_ns7__StreamBody__(struct soap*, ns7__StreamBody__ *, const char*, const char*);
    SOAP_FMAC3 ns7__StreamBody__ * SOAP_FMAC4 soap_in_ns7__StreamBody__(struct soap*, const char*, ns7__StreamBody__ *, const char*);
    SOAP_FMAC5 ns7__StreamBody__ * SOAP_FMAC6 soap_new_ns7__StreamBody__(struct soap*, int);
    SOAP_FMAC5 void SOAP_FMAC6 soap_delete_ns7__StreamBody__(struct soap*, ns7__StreamBody__*);
    SOAP_FMAC3 ns7__StreamBody__ * SOAP_FMAC4 soap_instantiate_ns7__StreamBody__(struct soap*, int, const char*, const char*, size_t*);
    SOAP_FMAC3 void SOAP_FMAC4 soap_copy_ns7__StreamBody__(struct soap*, int, int, void*, size_t, const void*, size_t);

    These also have definition associated with them.

    I agree there might be a deserializing issue. However, I’m not sure what part of the gSoap API code needs to be changed. Is there a work around?

  22. Alternatively, do you know how I can see the SOAP return message. This will confirm whether anything is being returned in the message body?

  23. I see that the call to the method is not successful. It returns -1 error

    “myProxy.DownloadDeal(input,output)”

    Does that give us any help?

  24. According to what you said previously, there is a buffer that contains the data, but gSOAP simly failed to de-serialize the structure. It is not about changing gSOAP api methods, it is about implementing your own de-serialization function as described in the link I gave before.

  25. I think the last message I sent got skipped. I was wanting to know how can I see the SOAP response message so as to verify that the client is receiving the stream in the Body. Is there a method in gSoap API which allows me to do this?

  26. Should’nt there be a way I can atleast see the serialized data to make sure the service is doing its job?

  27. Actually, you have plenty of options to ensure service returns data.
    At first, chances are soap->buf mentioned by you is the buffer containing raw data. At second, you can get Wireshark to see what is being sent over the network (it is generally a good idea to install network sniffer once you are in network programming).

  28. gSoap doesn’t have any method for this purpose?

  29. gSoap doesn’t have any method for this purpose?

    Not sure. Take a look at its documentation, it is quite an easy to deal with.

  30. Thanks a ton. Will u be around in case I need more help and advice. Is it possible to reach u any faster through an email?

  31. No porblem at all. BTW, you have just given me an idea for the next port about gSOAP/WCF.
    With all time zones issues this blog is the most reliable way to get me 🙂

  32. Hi Vital,
    Is there a way I can send my log file to you? I want to discuss regarding the issue I was having with deserialization of WCF data.

    Please let me know.

    Thanks,
    Vishal

  33. Hi Vital,
    I turned the debug on and was able to see my SOAP response message. However, the body tag for the FileStream contained this:

    ***************************************************************
    below this line it looks like the binary stream data. Shouldn’t this have been enclosed in the body tag???
    ***************************************************************

    –uuid:6e5371b3-9fca-4914-be46-dba2957546c9+id=1
    Content-ID:
    Content-Transfer-Encoding: binary
    Content-Type: application/octet-stream

     ÿÿÿÿ  System.Collections.ArrayList _items_size_version         
     OMkmv.SFW.WebService.Util, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 7Mkmv.SFW.WebService.Util.GZipCompress+SerializeFileInfo fileName
    fileBuffer  ACE05RM2.WB     ACE05RM2.WC
       ACE05RM2.WS  ø+  ƒ¸í }D scenario  *! A’j¾ýÚ4¿ß¿wJsÊý
    “»˜‚«¾ïÛ¾îû@½÷íÛ§iÛm»»Bç:©\js’²
    Ñ52 åRc2®‘T²Zl‹”ÇFj`؁YR2±x+ï¾Ïs¶ÙÛvÙaM$H$ŒKÐøf!­>ð­à¼Qᘼw‚ñ! à¼Wð¼/º
    áI É ñ>HÿÕµ²ÈÜbôtƒÁ`¯wÛÿY’×`!ˆB·[Sà#5lz
    áʧXÄ1©UhÌX!-O–PT`ÕùN‹@¸ è©{ŽŽ|ceÔ3­P‘P=>H©j; @¬•äF ò´½

  34. It looks like Im getting the serialized filestream as an attachment instead of getting it as part of the SOAP body. I don’t know how I can get that stream data.

    I tried calling my service from SoapUI test utility and it returned the filstream as an attachment in the tag:

    Can you help me understand this Vital?

    Thanks,
    Vishal

  35. Hi Vital,
    I’m still not able to figure out where this deserialization code should be called from within gSoap API. I can receive the file stream and can see the size of the file stream in the binary object on C++ client side, however, I still notice that the __ptr field is empty.

    I would really appreciate any help from you since I’ve been stuck on this issue for some while now.

    Thanks,
    Vishal

  36. Hi,

    According to what I see WCF serialized file stream data as binary and apparently used compression. I am in doubts gSoap can decode it by itself.
    Ar you sure you did not try to used base64 encoding on WCF side?

  37. Hi Vital,
    The WCF service is using BinaryFormatter to serialize the memory stream on WCF side.

    I am able to read the stream characters when I debug the c++ client. Also, __size field is getting set but __ptr field is still empty.

    I can incorporate the deserialization function, however, for that I first need to receive the serialized data which I can’t find in a variable.

    I really need to get this resolved since I feel I’m too close to the solution but really need help now and can’t find any other support from gSoap.

    Please help.

    Thanks,
    Vishal

  38. BTW, did you try to make gSoap to generate binary deserializer for you like shown here?

  39. I tried the following options for generating proxy files:

    wsdl2h -o myService.h http://localhost:2714/DealFileService.svc?wsdl

    soapcpp2 -1 -C -i -I ..\..\import -t -x myService.h

    Do I need to include -s option? also, Do I need to include typedef.dat in the .bat folder?

  40. Hi Vital,
    I still don’t have any clue on this issue. Please can you provide some more ideas.

    Thanks,
    Vishal

  41. G’day,

    I’ll try to write a simple test for it once I have a moment.

  42. Hi.
    I’m looking at setting up something similar on a GNU/Linux client in order to test that it works for our companies clients. Some may be using other clients than windows.

    Do you have any experience on this platform?
    I’m reasonably familiar with GNU/Linux as a user.
    Any help or direction in this would be helpfull.

    • Should not be a problem at all. You’ll need a gsoap (not sure about the name though) library. I bet it is already available in most Linux repositories. For instance, it is already there in Debian (here) And gcc, of course. If you have no experience writing and compiling programs Linux, you should probably start from some of make/gcc tutorials.

      I originally did it on Linux and for Linux.

  43. Sounds good vital.
    I’m using debian.
    I havn’t done any development on Linux. Only Windows so far.
    Thanks for the advice!

  44. Hi,

    I am using gSOAP 2.7.9l for generation of client side code i.e proxy ( via 2 WSDL file ) to connect to 2 different webservice in VC++ 2005 framework. soapStub and soapClient file is created. Now stdsoap2.cpp and stdsoap2.h file is common for both the stub files.

    I got the linking error :
    error LNK2001: unresolved external symbol “public: virtual void __thiscall ns1__submitMessage::soap_default(struct soap *)” (?soap_default@ns1__submitMessage@@UAEXPAUsoap@@@Z)

    Can any one advise on the same error.
    Thanks,
    Vijay

  45. Thank you very much! This info and your answers on questions in comments was very usefull to me!

  46. Hi Vital,
    I am trying to use the gsoap and following is my test client code –
    1 #include “soapUSCOREspcService_USCOREspcRequestBSProxy.h”
    2 #include “USCOREspcService_USCOREspcRequestBS.nsmap”
    3
    4 int main()
    5 {
    6 std::string sr = “2-1750638711”;
    7 USCOREspcService_USCOREspcRequestBS s;
    8 _ns1__Yahoo_USCOREspc__USCOREspcService_USCOREspcRequestBS_USCOREQueryTicket_USCOREInput *input =
    9 new _ns1__Yahoo_USCOREspc__USCOREspcService_USCOREspcRequestBS_USCOREQueryTicket_USCOREInput;
    10 _ns1__Yahoo_USCOREspc__USCOREspcService_USCOREspcRequestBS_USCOREQueryTicket_USCOREOutput *output =
    11 new _ns1__Yahoo_USCOREspc__USCOREspcService_USCOREspcRequestBS_USCOREQueryTicket_USCOREOutput;
    12 input->NamedSearchSpec = “”;
    13 input->LOVLanguageMode = “LIC”;
    14 input->ViewMode = “All”;
    15 ns2__queryType SRNumber;
    16 ns2__ServiceRequestQuery ServiceRequest;
    17 ns2__Yahoo_USCOREServiceRequest_USCOREIOQuery ns2__Yahoo_USCOREServiceRequest_USCOREIO;
    18
    19 SRNumber.__item = sr;
    20 ServiceRequest.SRNumber = &SRNumber;
    21 ns2__Yahoo_USCOREServiceRequest_USCOREIO.ServiceRequest = &ServiceRequest;
    22 input->ns2__Yahoo_USCOREServiceRequest_USCOREIO = &ns2__Yahoo_USCOREServiceRequest_USCOREIO;
    23
    24
    25 //input->ns2__Yahoo_USCOREServiceRequest_USCOREIO->ServiceRequest->SRNumber->__item = sr;
    26
    27 int err = s.__ns1__QueryTicket(input, output);
    28 if (SOAP_OK == err)
    29 {
    30 std::cout<<"Service returned\n";
    31 }
    32 else
    33 {
    34 std::cout<<"Error\n";
    35 }
    36 delete input;
    37 delete output;
    38 return 0;
    39 }

    Now, ……

  47. Hi !
    Thank you for your very interesting article.

    I made ​​a small demo project but found little problem.

    I’m very need it, hope you can help me.

    (WCF project – c #)

    public string strGetCustomerByID (int customerID)
    ————————————————– ——————————–
    CallWCFDemo demo project (c + +)

    similar to you.

    and error for me:

    error LNK1120: 14 unresolved externals E: \ CURRENT_WORK \ workspace \ MY PROJECT \ DLL \ CallWCFDemo \ Debug \ CallWCFDemo.exe CallWCFDemo
    —–
    error LNK2001: unresolved external symbol “public: virtual int __ thiscall _ns1__strGetCustomerByID :: soap_out (struct soap *, char const *, int, char const *) const” (? soap_out @ _ns1__strGetCustomerByID @ @ UBEHPAUsoap @ @ PBDH1 @ Z) E: \ CURRENT_WORK \ workspace \ MY PROJECT \ DLL \ CallWCFDemo \ CallWCFDemo \ CallWCFDemo.obj CallWCFDemo

    thanks !

  48. hello vital,

    very good tutorial, but when I tried to develop a wcf client c + + I have a little problem. When I compile my project (console application) I have no error, but I just can not manage to access my service (hosted locally “http://localhost/mexservice/implRoutingService.svc”).

    I followed exactly your tutorial.
    1 – wsdl2h.exe-o myservice.h http://localhost/mexservice/implRoutingService.svc?wsdl -> ok
    2 – soapcpp2.exe -i -I [path to import] myservice.h -C -> ok

    But no results when I run my application

    I don’t understand

    best regards,

    • Hi Marius,

      The first thing I always do when facing a problem with network app is starting Wireshark and watching network traffic.
      It won’t work with local traffic, you’ll need to host your service on another machine or virtual box.

  49. Hi Vital,

    I am able to build my project successfully but while running i am not getting output from the WCF service. I am getting this error in MyProxy buf :

    HTTP/1.1 415 Cannot process the message because the content type ‘application/soap+xml; charset=utf-8; action=”http://tempuri.org/IMessageService/GetData”‘ was not the expected type ‘text/xml; charset=utf-8’.
    Cache-Control: private
    Server: Microsoft-IIS/8.0
    X-AspNet-Version: 4.0.30319
    X-SourceFiles: =?UTF-8?B?

    can you please suggest the possible cause of error and its solution?

    Thanks in advance.

  50. Hi Vital,
    Can u please please help me?? I am very new to c++ as well as calling /invoking Web service using Gsoap in c++. i dont know which way I have to follow!! even I can’t understand the term like serialization… etc. currently I am using visual studio 2015 for implementing the project. i have the link of the wsdl web server. I designed a window form and the code of respective form has created. now there is a button called “Confirm”, when i click on that “Confirm” button it is going the respective method. now from here I have to call the web service to validate all data I put in those fields in the form. the fields are like “user_name” and “password”. so please tell me how to do that.

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Trackbacks and Pingbacks:

2 visitors online now
0 guests, 2 bots, 0 members
Max visitors today: 23 at 12:39 am UTC
This month: 57 at 04-16-2021 08:12 am UTC
This year: 57 at 04-16-2021 08:12 am UTC
All time: 332 at 11-22-2019 03:23 am UTC