Creating Manually Soap Request as string

I am trying to created SOAP request body that I need to post as string. I created the SOAP client and tried with this to get SOAP envelope. Can you suggest a way for this.

Set proxy=##Class(Client.Class.Client.Methodname).%New("Methodname")
Set proxy.Para1="a"
Set proxy.Para2="b"
Set tClient=##Class(Client.Class.Client).%New()
Do tClient.WriteHTTPContent(proxy,proxy.%RequestName,0,0,"","",.stream)

  • 0
  • 0
  • 272
  • 11
  • 3

Answers

Not sure exactly what you're trying to do or what problem  you're exactly facing (more details would be helpful) but, assuming you're trying to handle the soap body yourself instead of what the wizard generated then you can create a method to create the body and add the name to the WriteSOAPBodyMethod  property of the client class. It's not recommended to call Cache internal methods in your code. It's better to use any provided "hooks" if available.

To make it more clear, I've a REST service which takes 'SOAP Request' in it's body and forward the request to SOAP endpoint. Now I have to call this service where I need to frame a SOAP envelope. I created the SOAP client and it can call only SOAP service(end point is a class with SOAP webmethod class). But in this case a SOAP envelop needs to be created to pass it to REST's POST.

That makes it more clear, but not easier.

Class %SOAP.WebClient  is the base for any SOAP Client in Caché.
It has a property Transport to provide a registered class for alternate transport (or no immediate transport in your case)

check the code starting with Method InvokeClient(...
and look for transport within the next 50 lines to see how that works up to here

#; Make the request
Set sc=transport.DoSOAPRequest($this,Action,OneWay,stream,.responseStream)


Just to be clear:
I personally won't do it that way because of all the related maintenance risks.

Hacker's advice:
Create a SOAP client with Studio - Assist.
Send your request anywhere and hijack it with TCPtrace or WireShark or similar.
Now you have the string that you intend to modify and to send.

Anyhow, I'm somewhat surprised about the subject.

The trace can be captured through outside app. I need the string to be populated in objectscript.

YES. and once you have identified the content you should be able to modify it in object script according to your needs with $REPLACE, $TRANSLATE, ...... as any other string

If you don't do to detect the structure using TCPtrace or WireShark or similar you will not see it.

As I noted. It's an advice for hackers (and network engineers)

Well my question has to scoped within object script. Trying to find the way. How about creating the request using %XML.Writer.

Expected Output for class 'Myclass'

Class User.Myclass
{

Property Username As %String;

Property Password As %String;
 
}

<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>
        <Myclass xmlns="http://www.xyz.com/test">
            <Username>123</Username>
            <Password>123</Password>
        </GetSecurityToken>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

You may create a normal SOAP Client in Studio using the Wizard.

Then you add a transport class to display / dump your request. (example in SAMPLES)

Class SOAPDemo.Transport Extends %RegisteredObject
{
ClassMethod DoSOAPRequest(
 client As %SOAP.WebClient,
 Action As %String,
 OneWay As %Boolean = 0,
 stream As %FileBinaryStream,
 ByRef responseStream As %GlobalBinaryStream) As %Status
{

    write !,"**** SOAP Request Begin ****",!
    for  write stream.ReadLine(),! quit:stream.AtEnd
    write !,"**** SOAP Request End ****",!
    quit 
$$$OK
}
}

Example to use it :

SAMPLES>set soap=##class(SOAP.DemoProxy).%New()
 
SAMPLES>set soap.Transport=##class(SOAPDemo.Transport).%New()  ;; add cusomized transport
 
SAMPLES>try {write !,soap.Mission() } catch {}    ;; you don't get a reply, so ignore it
  
**** SOAP Request Begin ****
<?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><Mission xmlns="http://tempuri.org"></Mission></SOAP-ENV:Body>
</SOAP-ENV:Envelope>

**** SOAP Request End ****
 
SAMPLES>try {write !,soap.AddInteger(17,4) } catch {}
 
**** SOAP Request Begin ****
<?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><AddInteger xmlns="http://tempuri.org"><Arg1>17</Arg1><Arg2>4</Arg2></AddInteger></SOAP-ENV:Body>
</SOAP-ENV:Envelope>
**** SOAP Request End ****

 

so you get Envelope + Body well separated

I guess the output is written to i/o device. Do we need to change the i/o device to store in variable. May be we can use ^SPOOL global?

the WRITE is just to visualize the example

the loop in YOUR class could be: 

 for msg=1:1 set msg(msg)=stream.ReadLine() quit:stream.AtEnd 


but that's just standard COS programming. Nothing special. see here
Then you have the local array msg with your SOAP message
Similiar the Try{ } Catch {}  construct that ignores the error that you experience as you don't get a real SOAP response here.