|
|
Home /
Groups /
ColdFusion Talk (CF-Talk)
Consume NET web service with complex arguments
Hi all,Kris Jones 08/13/07 04:50 P did you ever get this figured out? I am coming across the same thingShane Trahan 09/06/07 10:08 A > did you ever get this figured out? I am coming across the same thingKris Jones 09/06/07 10:02 P Hi all, I'm trying to consume a .NET web service that has 2 arguments, one of which is complex. The webservice is expecting an xml type and an int type. I've looked at a lot of resources regarding this, and am still coming up broke. I've run the wsdl against the WSDL2Java tool, and looked at the .java file for the ws method I'm calling, and not getting any particularly good information out of it (it wants an argument of type _any, which from what I've read is the default .NET signature). From the wsdl: <s:element name="SOMEMETHODNAME"> $B!](B<s:complexType> $B!](B<s:sequence> $B!](B<s:element minOccurs="0" maxOccurs="1" name="somearg1"> $B!](B<s:complexType mixed="true"> $B!](B<s:sequence> <s:any/> </s:sequence> </s:complexType> </s:element> <s:element minOccurs="1" maxOccurs="1" name="somearg2" type="s:int"/> </s:sequence> </s:complexType> </s:element> Additionally, the call requires a header: <s:element name="SecurityHeader" type="tns:SecurityHeader"/> $B!](B<s:complexType name="SecurityHeader"> $B!](B<s:sequence> <s:element minOccurs="0" maxOccurs="1" name="SessionKey" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="ClientName" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="UserName" type="s:string"/> </s:sequence> </s:complexType> So, I've created a struct with an array for the first argument, and a simple key for the second argument, something like so: <cfset mystruct=structNew() /> <cfset mystruct.somearg1=arrayNew(1) /> <cfoutput query="myquery"> <cfset mystruct.somearg1[currentrow]=structNew() /> <cfset mystruct.somearg1[currentrow].EL1="#EL1#" /> <cfset mystruct.somearg1[currentrow].EL2="#EL2#" /> <cfset mystruct.somearg1[currentrow].EL3="#EL3#" /> </cfoutput> <cfscript> // Create the web service object. ws = CreateObject("webservice", "http://www.domain.com/webservice.asmx?WSDL"); // Setup the SOAP header addSOAPRequestHeader(ws, "", "SessionKey", "#variables.sessionkey#", false); addSOAPRequestHeader(ws, "", "ClientName", "MyClientName", false); addSOAPRequestHeader(ws, "", "UserName", "MyUserName", false); // Invoke the web service operation. my_result = ws.SOMEMETHODNAME(mystruct,1); </cfscript> I'm getting the error: Web service operation "SOMEMETHODNAME" with parameters {{somearg1={[{EL1={4760000-11513503999},EL2={111-222-4444},EL3={111-222-4445}... could not be found In the code above, I'm sending the 2nd argument via the call, straight-up. I've also tried adding that as an key/value pair in the struct, as in <cfset mystruct.somearg2=1 /> and then the call would be: my_result = ws.SOMEMETHODNAME(mystruct); Previously I'd tried passing in the XML string, or a CF XML object as well. I've verified that the XML format I was/am using is valid. What am I missing? Any suggestions for fixes? A better or easier way to approach this? Thanks, Kris did you ever get this figured out? I am coming across the same thing > did you ever get this figured out? I am coming across the same thing Hi Shane, I did find an approach that works for my situation. Here are some abbreviated notes I put together for our team: Note, you'll need to access the WSDL file, and soap descriptions for your webservice calls. Cheers, Kris ----------------------------------------- ColdFusion has the ability to consume (e.g., call) a webservice using it's CFINVOKE and CFINVOKEARGUMENT tags: <cfinvoke webservice="webservice wsdl address" method="ws method name" returnvariable="myreturnvar"> <cfinvokeargument name="ws parameter name 1" value="my param value" /> <cfinvokeargument name="ws parameter name 2" value="my param value" /> </cfinvoke> You can also wrap the arguments up in the cfinvoke tag itself, like this: <cfinvoke webservice="webservice wsdl address" method="ws method name" parametername1="my param value" parametername2="my param value" returnvariable="myreturnvar" /> Be aware that ColdFusion has, in it's CFInvoke tag, parameters called username and password. If the web service you are calling has attributes with these same names, your web service call will not work if you are using the simple form of CFInvoke like this: <cfinvoke webservice="webservice wsdl address" method="ws method name" username="myusername" password="mypassword" attributeN="value" returnvariable="myreturnvar" /> You must create a structure to hold your attributes, and pass that in the attributeCollection parameter instead: <cfset stArgs=structNew() /> <cfset stArgs.username="myusername" /> <cfset stArgs.password="mypassword" /> <cfset stArgs.attributeN="value" /> <cfinvoke webservice="webservice wsdl address" method="ws method name" attributeCollection="#stArgs#" returnvariable="myreturnvar" /> In general, when you are dealing with complex inputs to a webservice, you are probably better off just constructing the soap packet manually, and calling the webservice via cfhttp, rather than attempting to use cfinvoke on a webservice object, for example: <cfsavecontent variable="soap_packet"><cfoutput><?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Header> <HeaderName xmlns="name_space_address"> <headerparam1>#variables.sessionkey#</headerparam1> <headerparam2>ImpExpTestClient</headerparam2> <headerparam3>xmlservices</headerparam3> </HeaderName> </soap:Header> <soap:Body> <PN_SET_VENDORCOMBO xmlns="name_space_address"> <webserviceparam1>#variables.xmlstring#</webserviceparam1> <webserviceparam2>#request.integration_package_id#</webserviceparam2> </PN_SET_VENDORCOMBO> </soap:Body> </soap:Envelope> </cfoutput> </cfsavecontent> <cfhttp url="webservice_wsdl_address" method="POST"> <cfhttpparam type="HEADER" name="Content-Type" value="text/xml; charset=utf-8"> <cfhttpparam type="HEADER" name="Accept" value="application/soap+xml, application/dime, multipart/related, text/*"> <cfhttpparam type="HEADER" name="User-Agent" value="Axis/1.1"> <cfhttpparam type="HEADER" name="Host" value="dotted_notation_host_address"> <cfhttpparam type="HEADER" name="Cache-Control" value="no-cache"> <cfhttpparam type="HEADER" name="Pragma" value="no-cache"> <cfhttpparam type="HEADER" name="SOAPAction" value="URL TO WEBSERVICEorMETHOD"> <cfhttpparam type="HEADER" name="Content-Length" value="#len(trim(soap_packet))#"> <cfhttpparam type="BODY" value="#trim(soap_packet)#"> </cfhttp> In the cfhttp call above, note the URL, Host, SOAPAction, Content-Length, and BODY are dependent on your call. Everything else can remain static as shown. Also, when receiving complex structures back from a webservice call, remember that CFDUMP is your friend. When using CFINVOKE, very often the return value is inside an object returned by the web service. With our webservices, usually, you'll need to call the get_any() function on the object to get the actual return value. Which function is to be called is dependent on the type of value being returned, and certainly can be webservice method specific. The results from the get_any() (or whatever) call, will usually be an array--but not always--so again, CFDUMP is your friend. Finally, here are decent articles on consuming web services from/to .Net: http://coldfusion.sys-con.com/read/47199.htm Long forum discussion on consuming complex web services that require specific header and property attributes: http://www.adobe.com/cfusion/webforums/forum/messageview.cfm?catid=7&threadid=781179 And finally, here is an article on the nitty-gritty behind how ColdFusion utilizes Java to interface with most other web services, specifically having to do with complex web services, and how we get our type-less values to be typed correctly for the web-service being called. It's not inherently necessary to read it, but it is good information: When having to pass complex structures into a .Net webservice, read this excellent article, which you'll have to get from the WayBack machine, because it's no longer available on the authors' website: http://web.archive.org/web/20070309173903/http://hcc.musc.edu/research/shared_resources/xml_complex_types_to_cf_structure_notes.cfm And, while this article gives some approaches for dealing with complex calls, I still found that just writing the soap packet manually got me the results (and more easily). -----------------------------------------
|
Mailing Lists
|
Latest Fusion Authority Articles
|
||||||