PDA

View Full Version : Returning a query from a ColdFusion web service


cvleon
10-12-2004, 06:09 AM
Hello. Now that I've got Laszlo up and running on my Mac (couldn't get JRun to work, so I'm using the Tomcat package), I'm trying to get a simple Laszlo / ColdFusion MX (CFMX) application going.

I've got a Coldfusion Component (CFC) set up as a web service. It has one simple function, getData(), that returns a query (CF parlance for recordset). It seems that Laszlo can't automatically handle this complex datatype, even though it seems to be described in the WSDL. I hope someone can help me figure this out, since it would be great to be able to easily work with CFMX's native recordsets.


The specific error I'm getting is:

org.xml.sax.SAXException: Deserializing parameter 'getDataReturn': could not find deserializer for type {http://rpc.xml.coldfusion}QueryBean


Here's the Laszlo code (sorry, but I don't know how to make this format nicely):

<canvas debug="true" width="800" height="600" bgcolor="gray">

<debug x="15" y="15" width="415" height="500" />

<dataset name="myDset" />

<soap name="testSoap" wsdl="http://testapp.localhost/test.cfc?wsdl">

<method event="onload">
Debug.write('test soap service loaded');
Debug.inspect(this.proxy);
testSoap.getData.invoke();
</method>

<remotecall funcname="getData" dataobject="myDset">

<method event="ondata" args="value">
//debug.write('dataset:\n', value);
</method>

</remotecall>

</soap>

<text>This is my test app</text>

</canvas>


Here's the WSDL returned by CFMX:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://DefaultNamespace" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns1="http://rpc.xml.coldfusion" xmlns:impl="http://DefaultNamespace" xmlns:intf="http://DefaultNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"><wsdl:types><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://DefaultNamespace"><import namespace="http://schemas.xmlsoap.org/soap/encoding/"/><complexType name="ArrayOf_xsd_string"><complexContent><restriction base="soapenc:Array"><attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/></restriction></complexContent></complexType><complexType name="ArrayOfArrayOf_xsd_anyType"><complexContent><restriction base="soapenc:Array"><attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:anyType[][]"/></restriction></complexContent></complexType></schema><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://rpc.xml.coldfusion"><import namespace="http://schemas.xmlsoap.org/soap/encoding/"/><complexType name="QueryBean"><sequence><element name="columnList" nillable="true" type="impl:ArrayOf_xsd_string"/><element name="data" nillable="true" type="impl:ArrayOfArrayOf_xsd_anyType"/></sequence></complexType><complexType name="CFCInvocationException"><sequence/></complexType></schema></wsdl:types>
<wsdl:message name="CFCInvocationException">
<wsdl:part name="fault" type="tns1:CFCInvocationException"/>
</wsdl:message>
<wsdl:message name="getDataRequest">
</wsdl:message>
<wsdl:message name="getDataResponse">
<wsdl:part name="getDataReturn" type="tns1:QueryBean"/>
</wsdl:message>
<wsdl:portType name="test">
<wsdl:operation name="getData">
<wsdl:input name="getDataRequest" message="impl:getDataRequest"/>
<wsdl:output name="getDataResponse" message="impl:getDataResponse"/>
<wsdl:fault name="CFCInvocationException" message="impl:CFCInvocationException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="test.cfcSoapBinding" type="impl:test">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getData">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getDataRequest">
<wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace"/>
</wsdl:input>
<wsdl:output name="getDataResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace"/>
</wsdl:output>
<wsdl:fault name="CFCInvocationException">
<wsdlsoap:fault use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="testService">
<wsdl:port name="test.cfc" binding="impl:test.cfcSoapBinding">
<wsdlsoap:address location="http://testapp.localhost/test.cfc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>


And finally, the XML returned by the getData() method:

<wddxPacket version='1.0'><header/><data><recordset rowCount='3' fieldNames='foo,bar' type='coldfusion.sql.QueryTable'><field name='foo'><string>a</string><string>b</string><string>c</string></field><field name='bar'><string>1</string><string>2</string><string>3</string></field></recordset></data></wddxPacket>

bcourchaine
10-15-2004, 03:00 AM
Been working with Coldfusion MX web services for about a year now and have encountered similar errors when trying to pass cfquery results to non-CFMX web service consumers, cvleon.

CFMX implemented its own SOAP array type, QueryBean, to return CF queries. They're very handy if you're going from a CFMX web service to another CFMX server but not the SOAP type is not implemented in other SOAP engines and therefore not useful anywhere else.

I'd suggest packaging the cfquery result set into a standard SOAP array and passing that instead.

cvleon
10-15-2004, 07:02 AM
Thanks for the reply, bcourchaine! It's a shame that Laszlo doesn't support QueryBean. I bet it could be made to... I'll send in a feature request (since I'm probably not enough of a hacker to write it myself). Having to parse every recordset into a different datatype will be a lot of CF server overhead. It's too bad ColdFusion can't use recordsets and structs of arrays interchangeably, since they're so close to each other.

So what do you suggest in terms of creating compatible web services? Should the recordset be turned into:

a) a struct (hash) of arrays - this seems like the most efficient in terms of the size of the serialized XML. Does SOAP have hashes as a standard datatype?

b) an array of structs

c) something else I haven't thought of

Thanks for your input!

bcourchaine
10-16-2004, 05:17 AM
I'd just turn it into a plain-ol' zero-indexed 2D array and return that from the web service.

Much more commonly supported data type.

Here's how to do it if you've not done it before:

http://livedocs.macromedia.com/coldfusion/6.1/htmldocs/arrays18.htm

pc
10-18-2004, 05:46 PM
I've worked with arrays in cfm templates but hadn't passed one in a cfc as a soap web service. The example in that link is like what i've done before but how would you do as you said:

"I'd just turn it into a plain-ol' zero-indexed 2D array and return that from the web service."

When I have the cfquery results populate an array in the following:

<cfcomponent>
<cffunction name="getContactsArray" access="remote" returntype="array" output="true">
<cfquery name="selectContacts" datasource="test">
SELECT
FirstName,
LastName,
EmailAddress,
DaytimePhone
FROM
Contacts
ORDER BY
ContactsID
</cfquery>

<!--- Declare the array --->
<cfset returnArray=ArrayNew(2)>

<!--- Populate the array row by row --->
<cfloop query="selectContacts">
<cfset returnArray[CurrentRow][1]=FirstName>
<cfset returnArray[CurrentRow][2]=LastName>
<cfset returnArray[CurrentRow][3]=EmailAddress>
<cfset returnArray[CurrentRow][4]=DaytimePhone>
</cfloop>
<cfreturn returnArray>
</cffunction>
</cfcomponent>

then have the lzx pull the data from that web service wsdl similar to how cvleon did I get the following error:

rpc/rpc.lzx:276: reference to undefined property 'error'
getContactsArray remotecall onerror: undefined

what am I missing?
thankz

bcourchaine
10-19-2004, 04:29 AM
That errror looks like a Laszlo error, pc.

It seems to be complaining about "onerror", not the array you passed it.

I'm just getting started w/ Laszlo. Anyone else help here?

bsd12673
10-22-2004, 12:15 PM
I have a follow up question on consuming a CF based web service. When you use a 2 dimensional array and have two fields returned, i.e. id, name laszlo pulls those values in like "1,Ben".

I'm trying to use a combobox that has the id as the value and the name as the text displayed but I can only get both to show as text in the combobox. How can I strip out the id to be just the value and the name to show up as the text? This is what I have so far:

<view width="505" height="140" bgcolor="silver" layout="axis: y" >
<view>
<combobox id="cbox1" y="10" editable="false" width="200">
<textlistitem datapath="myDset:/item/*" text="$path{'text()'}" value="$path{'@value()'}" />
</combobox>
<text text="${'value: ' + cbox1.value}"/>
</view>
</view>

Thanks,
Ben

marcovth
10-22-2004, 01:14 PM
If you have a problem connecting to a MM CFMX
server you might want to try BlueDragon CFMX:
http://www.newatlanta.com/products/bluedragon/index.cfm

I think bluedragon should become open source too and
team up with laszlo.

- Marco.

Tyson
02-09-2005, 01:55 PM
I'm going to resurrect this thread in hopes that someone has learned something new since last October...

I, too, am trying to consume a CF web service that makes a query. Is there really no good way to perform this call and have data returned to a dataset? I've done what has been mentioned, but I'm having the same issue that Ben did.

-Tyson

russell
03-18-2005, 03:53 PM
Tyson,

I don't know how everyone else is doing this, but I've found a very simple way to get my CF data into Laszlo. Here's a sample CFM file:

<CFQUERY Name="MyQuery" Datasource="MySource" maxrows="50">
SELECT UniqueID, Stuff
FROM TABLE1
WHERE (Criteria = 1)
ORDER BY UniqueID
</cfquery>

<recordset>
<CFOUTPUT query="MyQuery">
<!-- You must ESCAPE some characters, ampersands, greater/less than, etc. -->
<name uniqueid="#uniqueid#" Stuff="#Replace(InstitutionName, "&", "&amp;", "ALL")#" />
</CFOUTPUT>
</recordset>

Then I can consume it easily with Laszlo.

I hope that helps.

Russell Schutte

P.S. I almost forgot one huge benefit for me. If you're a fusebox programmer, you simply change your DSP (display) files to output XML instead of HTML and then they are ready to be consumbed by Laszlo! So all your future development can still be Fusebox based!

pydyp
05-10-2007, 03:52 AM
More generic:

<cfquery name="myQuery" datasource="easynet_dev">
SELECT * FROM myTable ...
</cfquery>
<cfloop query="myQuery">
<cfoutput><RECORD></cfoutput>
<cfloop index="i" list="#myQuery.ColumnList#">
<cfoutput><#i#>#XMLFormat(evaluate(i))#</#i#></cfoutput>
</cfloop>
<cfoutput></RECORD></cfoutput>
</cfloop>