33

I am using Coldfusion9 to interact with a 3rd party SOAP service with which I need to both send and receive SOAP with attachments. I am having no issue in receiving the SOAP which may or may not have binary attachments by using ToString() around the HTTP content to convert the SOAP Body into a usable string, however the service requires that I send my response back using attachments as well which is where I am coming undone. I've just never done this in ColdFusion and i'm not exactly sure how I should be presenting this to the originating service so that the SOAP body is referenced via an ID.

Below is the parsing of the incoming SOAP data with attachments:

<cfset soapData = GetHttpRequestData()>

<!--- Loop over the HTTP headers and dump the SOAP content into a variable --->
<cfsavecontent variable="soapContent">
<cfoutput>      
    <cfloop collection = #soapData.headers# item = "http_item">
    #http_item#: #StructFind(soapData.headers, http_item)# #chr(10)##chr(13)# 
    </cfloop>
    request_method: #soapData.method# #chr(10)##chr(13)# 
    server_protocol: #soapData.protocol# #chr(10)##chr(13)# 
    http_content --- #chr(10)##chr(13)#  
    #toString(soapData.content)#
</cfoutput>
</cfsavecontent>

<!--- Save file to flat file --->
<cffile action = "write" 
    file = "#expandPath('../')#logs/#dateFormat(now(),'dd-mm-yyyy')#_#timeFormat(now(),'HHmmss')#.txt" 
    output = "#soapContent#">

Now I am currently presenting the response as a full SOAP XML response containing the body as inline XML with the required STATUSCODE (see below).

<cfsavecontent variable="strResponse">
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
    <SOAPENV:Body>
        <ns1:processResponse xmlns:ns1="urn:TripFlow" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <STATUSLVL>00</STATUSLVL>
        </ns1:processResponse>
    </SOAP-ENV:Body>
</SOAPENV:Envelope>
</cfsavecontent>

<!--- Strip all whitespace between tags --->
<cfset strResponse = trim(ReReplaceNoCase(strResponse,'(>[\s]*<)','><','ALL'))>

<!--- Output the XML response to the soap service --->
<cfoutput>#strResponse#</cfoutput>

The above response is throwing an error because the SOAP service requires the response to be sent referencing the body message as an attachment exactly like follows from the documentation:

HTTP/1.1 200 OK
Date: Thu, 01 Apr 2010 09:30:25 GMT
Server: Jetty/5.1.4 (Windows XP/5.1 x86 java/1.5.0_15
Content-Type: multipart/related; boundary=soaptestserver; type="text/xml"; start="<theenvelope>"
SOAPAction: ""
Content-Length: 796
Connection: close

--soaptestserver
Content-ID: <theenvelope>
Content-Transfer-Encoding: 8bit
Content-Type: text/xml; charset=utf-8
Content-Length: 442

<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAPENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"><SOAPENV:
Body><ns1:processResponse xmlns:ns1="urn:TripFlow" SOAPENV:
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><message
href="cid:thecontentmessage"/></ns1:processResponse></SOAP-ENV:Body></SOAPENV:
Envelope>

--soaptestserver
SOAP Interface
www.travelsolutions.com 123
travel solutions online V14.0 External System Integration
Content-ID: <thecontentmessage>
Content-Transfer-Encoding: 8bit
Content-Type: text/xml; charset=utf-8
Content-Length: 65

<?xml version="1.0" encoding="UTF-8"?><STATUSLVL>00</STATUSLVL>
--soaptestserver--

Any help would be greatly appreciate as i'm really hitting my head up against a wall on this one. Thanks!

Phil Rasmussen
  • 635
  • 1
  • 7
  • 20
  • 1
    Not something I've played with. Looks like you're trying to build the request a string; I'm guessing you're hitting either a malformed XML or namespace issue. Instead of string building, I'd use ColdFusion's XML support and the `AddSOAPRequestHeader()` function: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_a-b_03.html#5050827 the link has an example of sending and consuming SOAP. – orangepips Feb 14 '11 at 02:25
  • Well the developers at the other end have basically said their logs show I am trying to send the response inside the SOAP body direct when in fact i need to include it as an attachment or it won't work. So the "00" response line needs to be referenced from within the main SOAP response and this is what i'm unsure of in CF. It almost sees like a hyperlink reference within SOAP requests. Why they want it this way is another question altogether as this seems to be overcomplicating things :S – Phil Rasmussen Feb 14 '11 at 04:58
  • Understand. I'd suggest studying how ColdFusion allows you to do something along the lines of: `ws = createObject('webservice', 'http://domain/file.ext?wsdl')` where you can then do `ws.method(argument=value)` calls. My first link demonstrates that. – orangepips Feb 14 '11 at 14:53
  • 1
    Try looking into SoapUI, it's a great tool to help iron out issues be it your code or theres. – Stefano D Feb 15 '11 at 16:01
  • Thanks for the response guys and that SoapUI site came in really handy. I've ended up going back to reading up on SOAP attachments over MIME and it seems the key here is creating custom HTTP headers using the Content-ID header to associate a unique ID with a MIME part. This should in theory allow me to build my response and creation the body attachment association to the parent envelope. – Phil Rasmussen Feb 17 '11 at 00:32
  • @Orangepips i had a good read over the AddSOAPRequestHeader() and it doesn't seem to allow me to deal with attachments over MIME? So since my service is merely a listener that logs a request and presents a response, i need to present the calling SOAP service with a valid response using MIME parts. I'll give this a crack and let you know if it worked. Thanks! – Phil Rasmussen Feb 17 '11 at 00:33
  • 1
    Your question is getting a decent amount of traffic, if you found an answer you should post it to help out the community. Good luck. – Stefano D Oct 14 '11 at 16:53
  • Hi Stefano sorry i hadn't seen the notifications on this, i haven't yet found a solution to this issue, however i did change the response to no longer return the SOAP attachment just the basic SOAP response as per the vendor's request. The question still stands if anyone has managed to achieve this using ColdFusion and manipulating the MIME headers. – Phil Rasmussen Feb 27 '12 at 02:45

2 Answers2

1

Whenever I interact with SOAP services I usually end up using something similar to this. It generally works. Notice that I have some place-holder text in there that you would need to replace with the appropriate values for your 3rd party provider.

<cfsavecontent variable="soap">
<?xml version="1.0" encoding="UTF-8" ?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
   <soapenv:Header/>
   <soapenv:Body>
      <ns1:processResponse xmlns:ns1="urn:TripFlow" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <statuslvl>00</statuslvl>
      </ns1:processResponse>
   </soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>

<!--- Invoke web service to send message--->
<cfhttp url="http://3rd-party-url-here" method="post" timeout="10">
<cfhttpparam type="header" name="content-type" value="text/xml" />
<cfhttpparam type="header" name="SOAPAction" value="""3rd-party-method-name-here""" />
<!---<cfhttpparam type="header" name="accept-encoding" value="no-compression" />  sometimes this is needed --->
<cfhttpparam type="header" name="content-length" value="#len(soap)#" />
<cfhttpparam type="header" name="charset" value="utf-8" />
<cfhttpparam type="xml" name="message" value="#trim(soap)#" />
</cfhttp> 
Miguel-F
  • 13,450
  • 6
  • 38
  • 63
1

It has been a while since I worked with ColdFusion. The last I remember, it did not provide a harness to send a SOAP attachment. I solved this issue by writing a custom CFX tag with Java that did it for me. The entire SOAP call will need to go through the tag.

The Java library you want to look at if you choose to do this is javax-ws. You also need to find out if the service call has to use MTOM.

Sorry that is not a direct solution, but it is what I had to do with CF a few versions back.

Chad
  • 265
  • 1
  • 14
  • Hi Chad we currently don't have java resources within the team so this option would be a little tricky and require outside intervention, and I was really hoping for a definitive yes/no answer to purely use CF9 to achieve this SOAP response which seems close to possible but it sounds like you were using an older version of CF and it probably wasn't supported then. – Phil Rasmussen Feb 27 '12 at 02:48
  • Apologies for the delayed response it's been a long annual leave and a while since I jumped back into SO! – Phil Rasmussen Feb 27 '12 at 02:49