Assigning header values when calling SOAP methods

Assigning header values when calling SOAP methods

  

When invoking a SOAP service, I need to be able to specify SOAP header values to the server.

How would you go about solving this in Outsystems? 

Some background information:

Let's assume that the webservice is a simple hello world webservice that responds with the input-name that you give it, but in order to serve the request, it has to have some SOAP 5 header values specified, in addition to the input-name. My SOAP envelope that I want to send has look similar to this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:x="http://x-road.eu/xsd/x-road.xsd" xmlns:prod="http://webservice.x-road.eu/producer">
   <soapenv:Header>
      <x:service>webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>
   </soapenv:Header>

   <soapenv:Body>
      <prod:helloWorld>
         <request>
            <inputName>Mr. Bean</inputName>
         </request>
      </prod:helloWorld>
   </soapenv:Body>
</soapenv:Envelope>

When I connect through service studio, those header attributes cannot be set - service studio only gives me ability to specify attributes of the SOAP <body> section. 

I don't find anywhere to specify the SOAP <header> section:

I need to solve this for about 10 different webservices / 20 methods (and counting) so I need to solve it more generally than a new development approach for every service/method, if possible. 

My thought was to perhaps use an IIS plugin, where these values are added on-the-fly before the request leaves the OS IIS server, but I'm not sure how this would be approached.

Anyone have an idea of what is "the Outsystems way" of solving this (specifying SOAP header values)?

Hi Andras,

Did you look into this https://www.outsystems.com/forums/discussion/21680/how-to-add-soap-header/? Basically there is a extension called EnhancedWebReferences to help you with that.

Regards,

Marcelo

Hi Marcelo,

Thank you for your reply - this seems to be what I'm after. I'm relative new to this - could you point me towards a document or course that explains how I can get started in using this extension? Is this something that needs to go into Integration Studio and Visual studio then, or is service studio, with the correct dependencies enough? Thanks!

Hi Andras,

On service center you need to add the reference to EnhancedWebReferences > SetWebReferenceSoapHeaders.

To this action you need to pass the WebReferenceName and a list of soapheaders. For this list append to it a record with the element with this       

      <x:service>webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>

On the post I sent you there is a example with it that I'm also attaching here

Hope this helps.

Regards,

Marcelo



Perfect, Thank you

I saw that image on the original post, but didn't figure out how to add the reference. 

Will check with the admins to add access to Service Center, or make them add the reference, and then I'll give this a try.

/Andras

Hi Andras, 

Sry my mistake i meant service studio. you just need to manage the dependencies there and add the correct action from EnhancedWebReferences extension

Regards,

Marcelo

Hi again Marcelo, 

Thanks for spending time on this. I tried the approach you mentioned, and it doesn't recognize the "x:" in the header:

'x' is an undeclared prefix. Line 1, position 2.

I saw a similar report in the forum-post that you referred to, and tried to do this:

"<x:service xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice.helloWorld.v1</x:service>
 <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
 <x:userId>12e3f1f2aa4536c4687</x:userId>
 <x:producer>webservice</x:producer>
 <x:consumer>my-consumer</x:consumer>"

...then it responds: 

"There are multiple root elements. Line 2, position 8"

So there is a difference in my xml, because I don't have an surrounding xml-tag for my headers. 

Edit: So how would I specify the xmlns:x, pointing to the xsd ?
This is probably not the correct question - because now the issue is that these attributes are all on the root level.

I have attached an overview of my configuration:

Thanks, 

Andras

Just to add a little experiment to this approach, I made some attempts to get the message accross to the service:

Attempt 1:

"     <x:service>webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>"

Attempt 1 – Response:


Attempt 2:

"     <x:service xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>"

Attempt 2 – Response:

Attempt 3:

"  <soapenv:Header>
      <x:service xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>
   </soapenv:Header>"

Attempt 3 – Response:

Attempt 4:

"  <soapenv:Header xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
      <x:service xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice.helloWorld.v1</x:service>
      <x:id>12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId>12e3f1f2aa4536c4687</x:userId>
      <x:producer>webservice</x:producer>
      <x:consumer>my-consumer</x:consumer>
   </soapenv:Header>"

Attempt 4 – Response:

Attempt 5:

"  <soapenv:Header xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
      <x:service xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice.helloWorld.v1</x:service>
      <x:id xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">12af31e54c648b434d3f213548a432ae11</x:id>
      <x:userId xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">12e3f1f2aa4536c4687</x:userId>
      <x:producer xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">webservice</x:producer>
      <x:consumer xmlns:x=""http://x-road.eu/xsd/x-road.xsd"">my-consumer</x:consumer>
   </soapenv:Header>"

Attempt 5 – response:

So this time it reaches the backend server, but the xml is not consistent with what it should look like, and it therefore reports this error:

The apache server of the receiving server is now receiving the request, but logs the following:

consumer_proxy: message: consumer_proxy returned fault message (invalid soap message: Header sub tag 'consumer' is missing, failed to read query)

So it looks like it still doesn't follow the initial xml structure, that I'm trying to send (which is the one I mentioned in the initial post).

I don't have access to ServiceCenter, so is there a way, outside ServiceCenter, to view what the XML SOAP message finally looked like, when it was being sent to the web service? I suspect that the format of the message has now become something like this:

Envelope
 - Header
 - - Header
 - Body

Hi Andras, I use this tool to see what the platform is sending: https://beeceptor.com/

You just need to create a new endpoint and set this endpoint's address in Service Center in order to redirect your message.

Solution

Hi Andras,


I'm sorry that you got stuck trying to solve this problem.

You were on the right track with your Attemp 2. The problem is that you want to add 5 SOAP headers so you can't just add all the XML text at once. This is different from adding an header that has several elements inside it and it's why you have to do  5 appends to the SOAPHeader List.

The error message "There are multiple root elements. Line 2, position 8" is a bit unclear but is related to that.

Also, it might be necessary to include the namespace declaration

xmlns:x=""http://x-road.eu/xsd/x-road.xsd""

to avoid the 'x' is an undeclared prefix error


Hope this helps.


Best regards,

Pedro Guimarães

Solution

Hi Pedro and Joao, 

Thx for responding. @Joao, I think beeceptor expect REST requests (?) - I wan't able to test this fully.

@Pedro, I tried your approach, and I was able to get this working from your suggested approach. I was able to specify all the header-values in one assignment step, but adding these values to the SoapHeaderList was done one at a time.

Here's my approach (if someone hits this challenge in the future).

For reuseability, I guess these steps could be abstracted into a component with 5 properties, somehow, which could become one function/method too set the headers. 

Then it could be based on parameterized values or local variables of the calling module, every time we invoke any webservice method in the x-road platform, right?

Hi Andras,

Yes you are right. I'm glad you were able to solve this.


Cheers,

Pedro G.

Andras Eliassen wrote:

Hi Pedro and Joao, 

Thx for responding. @Joao, I think beeceptor expect REST requests (?) - I wan't able to test this fully.

@Pedro, I tried your approach, and I was able to get this working from your suggested approach. I was able to specify all the header-values in one assignment step, but adding these values to the SoapHeaderList was done one at a time.

Here's my approach (if someone hits this challenge in the future).

For reuseability, I guess these steps could be abstracted into a component with 5 properties, somehow, which could become one function/method too set the headers. 

Then it could be based on parameterized values or local variables of the calling module, every time we invoke any webservice method in the x-road platform, right?

Beeceptor works fine with SOAP as well. But good you've solved it..