Adding soap header to imported WSDL

Primary tabs

SOAP, Ensemble

I have an imported WSDL from SalesForce and I am trying to send a login-request to the SalesForce-servers via InterSystems. The login requires a username and a password in the body, and an organizationId in the header. I am having trouble filling the organizationId in the header.

Via SoapUI I can send a successfull message to the SalesForce-servers. The message should look like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
   <soapenv:Header>
      <urn:LoginScopeHeader>
         <urn:organizationId>MyOrganizationId</urn:organizationId>
      </urn:LoginScopeHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:login>
         <urn:username>MyUsername</urn:username>
         <urn:password>MyPassword</urn:password>
      </urn:login>
   </soapenv:Body>
</soapenv:Envelope>

In InterSystems Studio, I firstly imported the WSDL using the Studio's Soap Add-in. Among other things, this gave the following results:

1. A business operation class containing the login method:

Method login(pRequest As Request.loginRequest, Output pResponse As Response.loginResponse) As %Library.Status
{
 Set ..Adapter.WebServiceClientClass = "SforceService.Soap"
 Set tSC = ..Adapter.InvokeMethod("login",.result,pRequest.username,pRequest.password) Quit:$$$ISERR(tSC) tSC
 Set tSC = pRequest.NewResponse(.pResponse) Quit:$$$ISERR(tSC) tSC
 Set pResponse.result=$get(result)
 Quit $$$OK
}

2. A webclient class containing the login-method (proxy?_

/// Login to the Salesforce.com SOAP Api
Method login(username As %String(REQUIRED=1), password As %String(REQUIRED=1)) As SforceService.tns.LoginResult(XMLNAME="result") [ Final, ProcedureBlock = 1, SoapBindingStyle = document, SoapBodyUse = literal, WebMethod ]
{
 Quit ..WebMethod("login").Invoke($this,"",.username,.password)
}

3. The webclient class also contains an XdataMap noting that the LoginScopeHeader may be included with the login-request. The LoginScopeHeader contains the organizationId.

...

  <method name="login">
    <request>
      <header name="LoginScopeHeader" class="SforceService.tns.LoginScopeHeader"/>
    </request>
  </method>

...

As you can see the Header is referred to, but not included in as a parameter in the method.

Of course, I need to expand the method so that I can pass organizationId as a parameter. A first step in to this solution would be to hard code the organizationId in login-request. In the InterSystems documentation I found an example how to add the header using the HeadersOut-function ( https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY... ). I implemented this in the web client class as follows:


/// Login to the Salesforce.com SOAP Api
Method login(username As %String(REQUIRED=1), password As %String(REQUIRED=1)) As SforceService.tns.LoginResult(XMLNAME="result") [ Final, ProcedureBlock = 1, SoapBindingStyle = document, SoapBodyUse = literal, WebMethod ]
{
  Set header=##class(SforceService.tns.LoginScopeHeader).%New()
  Set header.organizationId = "MyOrganizationId"
  Do ..HeadersOut.SetAt(header,"SforceService.tns.LoginScopeHeader")

 Quit ..WebMethod("login").Invoke($this,"",.username,.password)
}

However, when I compile and run this code and view the soap log the header is still missing:
 

08/16/2017 10:55:13 *********************
Output from Web client with SOAP action = 
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:s='http://www.w3.org/2001/XMLSchema'>
  <SOAP-ENV:Body><login xmlns="urn:enterprise.soap.sforce.com"><username xsi:type="s:string">test</username><password xsi:type="s:string">test</password></login></SOAP-ENV:Body>
</SOAP-ENV:Envelope>

What did I do wrong?

 

Replies

Okay, I resolved this by adding the code to the Business Operation class instead:

 Set header=##class(SforceService.tns.LoginScopeHeader).%New()
 Set header.organizationId= "MyOrganizationId"
 
 Do ..Adapter.%Client.HeadersOut.SetAt(header, "SforceService.tns.LoginScopeHeader")

Tom, maybe re-post that information as an Answer rather than a Comment. Then you can accept your own answer (set the checkmark alongside it), so your question no longer lists as "unanswered".

Had to deal with the same issue.

I just edited the WSDL file and added the soapAction value to each method,

Took a few minutes, but that's all i had to do. Try to avoid using code where code isn't necessary.

In case that in the future something will change, you will have to deal with it on a code level, possible, but it's easier to just reconfig the new WSDL file or request the full version from SF\the integrator you're working with, without trying to figure out what that piece of code is meant to do after 2 years, and then poking around with it.

Good luck

This was the answer:

I resolved this by adding the code to the Business Operation class instead:

 Set header=##class(SforceService.tns.LoginScopeHeader).%New()
 Set header.organizationId"MyOrganizationId"
 
 Do ..Adapter.%Client.HeadersOut.SetAt(header"SforceService.tns.LoginScopeHeader")