📜 ⬆️ ⬇️

We write web service using gSOAP

What is it about?


Sometimes in the old and good C ++ there is a need for the implementation of SOAP services. Of course, true fans of programming rush to write the server themselves, but I prefer not to waste time and use ready-made libraries. Today I want to cover (quite a bit) the topic of using the gSOAP library in my C ++ applications as a server.

Tools


I will use Visual Studio 2010 SP1 in my story, but I will immediately mention that gSOAP works great on other platforms and compilers, and not just on Windows.

The library itself can be downloaded here [http://www.cs.fsu.edu/~engelen/soap.html] (I used v2.8.2).

Formulation of the problem


It is required to develop a payment acceptance service (well, of course, I lie), working according to the protocol.
The system has only one pseudo-signature method:
void MakePayment([IN] int qty, [OUT]int& errorCode, [OUT]string& message)

Go!


The process of generating server code in gSOAP is almost completely automated. Inside developed its own service description language, very similar in grammar to C with the elements "++". So we don’t have to even bathe with learning WSDL (but it’s still worth knowing about it).
')
Moreover, we were incredibly lucky, because the gSOAP distribution already contains compiled processors for this language for popular platforms, including Windows (believe me, compiling it with your hands (and even on Windows) is hardly a pleasure for you because of the large number of dependencies on opensource libraries, which you will also have to build ...).

So, we climb into the gsoap \ bin \ win32 \ directory and see two programs there. soapcpp2.exe is responsible just for what we need - processing a C-like service description language into server code, client proxy (if needed), wsdl descriptions and examples of soap request- reply- envelopes. Next is wsdl2h.exe - this utility allows you to run WSDL description of the service and at the output get a description of the service in a si-like language for further use in soapcpp2.exe. We need only the first one, because We do not have a description of the service on WSDL yet.

You can view the help page for each utility using the –help key. I will not list all the options here, because Many things will suit us by default, and the options that I use are fairly obvious from the help.

Server


Let's start with the description of the service. It is produced in files, usually with the h extension. We name the file paymentservice.h and enter literally the following:
 //gsoap ns service name: paymentssl //gsoap ns service style: rpc //gsoap ns service encoding: encoded //gsoap ns service namespace: urn:paymentssl //gsoap ns service location: http://localhost:9999 //gsoap ns service method-action: MakePayment urn:MakePayment typedef int xsd__int; typedef char* xsd__string; enum t__status // remote status: { STATE_OK, // ok STATE_FAIL // fail to process }; class t__result { public: enum t__status errCode; xsd__string message; }; int ns__MakePayment(xsd__int qty, t__result* result); 


Parameters for processing SOAP messages directly are specified as a “magic comment” (first lines). It makes no sense to dwell on them. they are almost a copy of standard SOAPs. Unless the format method-action is worth explaining - the first argument for it is the name of the method, and the second is the actual SOAPAction.

Run soapcpp2.exe -2 -i -e paymentservice.h
I will explain the parameters:


The result will be a bunch of files. Let us analyze them in order:


Here is the WSDL description that looks like:


The time has come to do server programming (in the server description there are SSL strings, but we’re not going to talk about encryption (and it’s supported)).

We program server


Create an empty console application that will not use Precompiled Headers. And add the generated files to the project.

The project takes the form:


The gSOAP core files are also added to it: stdsoap2.cpp and stdsoap2.h .

I immediately added the PaymentServiceImpl class in which I plan to implement the service.
In order for everything to gather, it is necessary to determine the function
 paymentsslService::MakePayment(int qty, t__result *result) 

It is virtual (but not purely virtual), and my implementation class, PaymentServiceImpl inherited from paymentsslService and will overload this operation, so you have to declare it somewhere as a stub somewhere like this:
 // //implementation for generated code always return FAIL. //This method will be override in PaymentServiceImpl class // int paymentsslService::MakePayment(int qty, t__result *result) { return SOAP_ERR; } 

The constant SOAP_ERR defined in stdsoap2.h among others.

We will also add the implementation of the overloaded MakePayment function in the PaymentServiceImpl class.

It's time to endow the service with the logic of returning messages about the success of a operation with a numeric code and a text message.

The logic will be as follows:
1) if qty <0 then we generate an exception SOAP (SOAP FAULT)
2) if qty> 100 then we return the error code FAIL with the message "error"
3) otherwise, we return the error code OK without a message

Final implementation:
 // PaymentServiceImpl.h #pragma once #include "Autogenerated/soappaymentsslService.h" class PaymentServiceImpl : public paymentsslService { public: virtual int MakePayment(int qty, t__result *result); }; // PaymentServiceImpl.cpp #include "PaymentServiceImpl.h" #include "Autogenerated/paymentssl.nsmap" /*virtual*/ int PaymentServiceImpl::MakePayment(int qty, t__result *result) { this->mode = this->mode | SOAP_C_UTFSTRING; if(qty<0) { this->soap_senderfault("error!", "<error xmlns=\"http://tempuri.org/\">The input parameter must be positive</error>"); return SOAP_CLI_FAULT; } if(qty>100){ result->errCode = STATE_FAIL; char err[] = "error (2)!"; int len=strlen(err); result->message = reinterpret_cast<char*>(soap_malloc(this, len+1)); strcpy_s(result->message, len+1, err); result->message[len] = '\0'; } return SOAP_OK; } 


It's time to start the service and check whether it gives out anything or even we have come all the way in vain.
Enter main:
 #include "PaymentServiceImpl.h" int _tmain(int argc, _TCHAR* argv[]) { const int SERVICE_PORT = 9999; std::auto_ptr<PaymentServiceImpl> srv (new PaymentServiceImpl()); if (srv->run(SERVICE_PORT)) { srv->soap_stream_fault(std::cerr); exit(-1); } return 0; } 


Also, for debugging purposes, we point out the preprocessor directive DEBUG (studio puts _DEBUG).

It's time to check for which we need a client

Make customer


For the demonstration, we will quickly outline the C # client, it is very simple (although c ++ is not more difficult, I will show C # as an example to show the communication of heterogeneous means using a single protocol (for which SOAP itself was once thought)).

Add a new C # Console Project, then add a Service Refence to it. As the address, specify the path to the file paymentssl.wsdl .


In the properties of the project we will not forget to indicate that we are using the .Net4, and not the .NET4 Client Profile framework.

Here is the verification code:
 var proxy = new PaymentService.paymentsslPortTypeClient(); string msg; var errCode = proxy.MakePayment(out msg, 10); 

//
// yes, the studio (or rather, the svcutil utility) has a rather peculiar understanding of what the parameters should be,
// but the topic of “interaction with other systems and gSOAP” is extensive enough for this introduction
//


You also need to fix the generated app.config, enough of this:
 <configuration> <system.serviceModel> <bindings> <customBinding> <binding name="paymentssl"> <textMessageEncoding messageVersion="Soap12" /> <httpTransport/> </binding> </customBinding> </bindings> <client> <endpoint address="http://localhost:9999" binding="customBinding" bindingConfiguration="paymentssl" contract="PaymentService.paymentsslPortType" name="paymentssl"/> </client> </system.serviceModel> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration> 

Voila, we have a client who can even call the service (you can check it yourself) using the SOAP protocol.

What I did not tell




If it is interesting, then perhaps I will describe it in a separate post (as time will appear).
Thank you all and good luck with SOAP.

Source: https://habr.com/ru/post/121853/


All Articles