ITQuants blog

Calling a secured webservice in Sophis Risque

Nov 30

Written by:
11/30/2012 2:37 PM  RssIcon

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>
37.            <endpoint address="https://myserver:myport/rpservice_DEV/CommonService/"
38.                binding="basicHttpBinding" bindingConfiguration="CommonsSoap11"
39.                contract="WebService.Commons" name="CommonsSoap11" />
40.        >
41.    >
42.>

 

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.}

Tags:
Categories: Sophis

Search blog