Calling a secured webservice in Sophis Risque
Nov
30
Written by:
11/30/2012 2:37 PM
On the server side, several types of server, agreed in most cases by the Corporate architect, are used:
- IIS + .Net
- Websphere + Java
- ....
Depending of the type of webservers, the implementation in Sophis Risque, in C++, can be done easily or not. This post will describe the development done to access a secured webservice deployed on a Websphere webservice.
We tried to access to this webservice using managed C++. The problem resides on the fact that managed C++ is not using the .Net framework to access to the webservices, but the ATL SOAP instead. And since ATL SOAP is not maintained by Microsoft, we got a problem of connection on a secured (https) webservice developped in Java.
Thus, one of the solutions which was retained is to use the .Net framework in C#, exporting some class by making an assembly, and accessing it using the C++ managed. The development in Sophis Risque is still C++ native and calls a standard C API, developped in managed C++ and exporting these functions.
In Visual Studio VS2010, we used the class library C# wizard in order to create the C# assembly. Once the project created, in order to generate the proxy to the secured http server, just choose a "Add a service reference" when right-clicking on the project:
The following dialog should appear. Just type the address of the secured webservice and click on GO:

Once the proxy created, it can be used in some .Net 4.0 C# code as follow:
01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using System.Text;
05.
06.namespace ReportingParty
07.{
08. public class WebServiceCall
09. {
10. public static bool GenerateUSI(long entityId, ref string usi)
11. {
12. bool _result = false;
13. usi = "";
14. WebService.GenerateUSIInput[] _input = new WebService.GenerateUSIInput[1];
15.
16. _input[0] = new WebService.GenerateUSIInput();
17. _input[0].entityId = new WebService.ThirdParty();
18. _input[0].entityId.Code = entityId.ToString();
19. _input[0].entityId.RepositoryId = WebService.Repository.SOPHIS;
20.
21. WebService.CommonsClient _client = new WebService.CommonsClient("CommonsSoap11", "https://myserver.fr:myport/rpservice_DEV/CommonService");
22.
23. try
24. {
25. WebService.GenerateUSIOutput[] _output = _client.GenerateUSI(_input);
26. if (_output.Length > 0 && !_output[0].isError)
27. {
28. usi = _output[0].usi;
29. _result = true;
30. }
31. }
32. catch (Exception e)
33. {
34. }
35. return _result;
36. }
37. }
38.}
The "CommonsSoap11" binding mentioned above at line 21 corrresponds to the entry generated during the generation of the proxy into the app.config, which should look like this one:
01. version="1.0" encoding="utf-8" ?>
02.<configuration>
03. <system.serviceModel>
04. <bindings>
05. <basicHttpBinding>
06. <binding name="CommonsSoap11" closeTimeout="00:01:00" openTimeout="00:01:00"
07. receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
08. bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
09. maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
10. messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
11. useDefaultWebProxy="true">
12. <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
13. maxBytesPerRead="4096" maxNameTableCharCount="16384" />
14. <security mode="Transport">
15. <transport clientCredentialType="None" proxyCredentialType="None"
16. realm="" />
17. <message clientCredentialType="UserName" algorithmSuite="Default" />
18. >
19. >
20. <binding name="CommonsSoap111" closeTimeout="00:01:00" openTimeout="00:01:00"
21. receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
22. bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
23. maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
24. messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
25. useDefaultWebProxy="true">
26. <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
27. maxBytesPerRead="4096" maxNameTableCharCount="16384" />
28. <security mode="None">
29. <transport clientCredentialType="None" proxyCredentialType="None"
30. realm="" />
31. <message clientCredentialType="UserName" algorithmSuite="Default" />
32. >
33. >
34. >
35. >
36. <client>
38. binding="basicHttpBinding" bindingConfiguration="CommonsSoap11"
39. contract="WebService.Commons" name="CommonsSoap11" />
The second step to call the C# assembly is to generate the managed C++ wrapper which will export a standard C function that could be called into the C++ toolkit plugin. This standard Windows dll will contain the following code:
1 - the export of the function in some .h file:
01.// ReportingPartyC.h
02.#pragma once
03.
04.
05.#ifdef REPORTINGPARTY_EXPORTS
06.#define REPORTINGPARTY_API __declspec(dllexport)
07.#else
08.#define REPORTINGPARTY_API __declspec(dllimport)
09.#endif
10.
11.extern "C"
12.{
13. bool REPORTINGPARTY_API GetUSI(long entityId, char* usi, size_t length);
14.}
The implementation of the call to the C# assembly objects as follow:
01.// This is the main DLL file.
02.
03.#include "stdafx.h"
04.#include "ReportingPartyC.h"
05.#include "DotNetMacros.h"
06.
07.
08.bool REPORTINGPARTY_API GetUSI(long entityId, char* usi, size_t length)
09.{
10. if(!usi || length<=0)
11. return false;
12.
13. System::String^ _usi = gcnew System::String("");
14. bool _result = ReportingParty::WebServiceCall::GenerateUSI(entityId,_usi);
15. if(_result)
16. {
17.
18. char* szUsi = STRING_TO_CHAR(_usi);
19. strncpy_s(usi,length,szUsi,length-1);
20. RELEASE_CHAR(szUsi);
21. }
22. return _result;
23.}
The macro STRING_TO_CHAR and RELEASE_CHAR will be detailed in some other post, since it ca be reused for other projects. It permits the conversion of C# unicode string to a basic C ANSI one. Once exported as above, the standard C function can be easily be called in any C executable. In order to activate the call to the webservice, the app.config file should be renamed using the syntax and should be placed in the current working directory.
A standard call to this function could be:
01.// TestImplementation.cpp : Defines the entry point for the console application.
02.//
03.
04.#include "stdafx.h"
05.#include "..\..\ReportingPartyC\ReportingPartyC.h"
06.
07.
08.int main(int argc, char* argv[])
09.{
10. char _usi[256];
11. bool _ret = GetUSI(10001030,_usi,sizeof(_usi));
12. return 0;
13.}