AxisFault: ColdFusion Web Services And XML Data Types

Posted June 15, 2009 at 10:23 AM

Tags: ColdFusion

A little while ago, I was helping someone debug a ColdFusion, SOAP-Based, web service error. Web services in general are not easy to debug and the problem was not too obvious, so I thought I'd post it here. To narrow down the problem, I set up a sample web service with just enough logic to duplicate the error. Here is the remote ColdFusion component:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • output="false"
  • hint="I am a test web service component.">
  •  
  • <cffunction
  • name="Test"
  • access="remote"
  • returntype="string"
  • output="false"
  • hint="I take an XML argument.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Data"
  • type="xml"
  • required="true"
  • hint="I am the xml data."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = {} />
  •  
  • <!--- Get the value. --->
  • <cfset LOCAL.ValueNodes = XmlSearch(
  • XmlParse( ARGUMENTS.Data ),
  • "//value"
  • ) />
  •  
  • <!--- Get the value. --->
  • <cfset LOCAL.Value = LOCAL.ValueNodes[ 1 ].XmlText />
  •  
  • <!--- Return value. --->
  • <cfreturn LOCAL.Value />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see from the code, all this remote web service does it take an XML string, parse it, search for the value node, and return the text of that node. To invoke the web service, I simply created the XML data and posted it to the web service using CFInvoke:

 Launch code in new window » Download code as text file »

  • <!--- Build our WSDL Url. --->
  • <cfset strURL = (
  • "http://localhost" &
  • GetDirectoryFromPath( CGI.script_name ) &
  • "WS.cfc?wsdl"
  • ) />
  •  
  •  
  • <!--- Build our XML data. --->
  • <cfsavecontent variable="strData">
  • <data>
  • <value>Test</value>
  • </data>
  • </cfsavecontent>
  •  
  •  
  • <!--- Invoke the web service. --->
  • <cfinvoke
  • returnvariable="strResponse"
  • webservice="#strURL#"
  • method="Test"
  • refreshwsdl="true">
  •  
  • <cfinvokeargument name="Data" value="#Trim( strData )#" />
  • </cfinvoke>
  •  
  •  
  • <!--- Output the response. --->
  • <cfoutput>
  • #strResponse#
  • </cfoutput>

Nothing out of the ordinary going on here; but, when I invoke the web service, I get this ColdFusion error:

Cannot perform web service invocation Test. The fault returned when invoking the web service operation is:<br> <pre>AxisFault faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException faultSubcode: faultString: coldfusion.xml.rpc.CFCInvocationException: [coldfusion.xml.XmlProcessException : An error occured while Parsing an XML document.] faultActor: faultNode: faultDetail: {http://xml.apache.org/axis/}stackTrace:coldfusion.xml.rpc.CFCInvocationException: [coldfusion.xml.XmlProcessException : An error occured while Parsing an XML document.]

If you look at the error, you'll see that it was thrown "while Parsing an XML document." This parse is performed in the XmlSearch() method call. So, why is the XmlParse() method failing? After all, if it made it to the XmlSearch() method, then it means that the CFArgument of type, "XML," was fine.

The problem is that "XML" means something different in ColdFusion depending on where it is used. If it's used completely within the ColdFusion application, XML is the standard XML that we are used to dealing with - either an XML string or the ColdFusion XML document. Once, we leave ColdFusion and venture into the web service world, however, XML appears to be a different beast. If we add a CFDump to our remote access web service:

 Launch code in new window » Download code as text file »

  • <!--- Output ARGUMENTS. --->
  • <cfdump
  • var="#ARGUMENTS#"
  • format="html"
  • output="#ExpandPath( './dump.htm' )#"
  • />

... we get the following output:

 
 
 
 
 
 
XML Web Service Data Type Implicit Convesion. 
 
 
 

As you can see, the XML document that came through wasn't the XML data string that we passed in; it was the Xerces XML document (which, if I had to guess is the Java object that ColdFusion XML documents decorate). It seems that the due to the XML data type, ColdFusion tried to implicitly convert the XML string into an XML document. Because this is no longer an XML string, but a complex XML Java object, XmlParse() doesn't know what to do and throws the above error.

To get around this, all we have to do is change our CFArgument data type from "XML" to "String":

 Launch code in new window » Download code as text file »

  • <!--- Define arguments. --->
  • <cfargument
  • name="Data"
  • type="string"
  • required="true"
  • hint="I am the xml data."
  • />

This gets rid of the error completely and allows the web service to return.

So, the moral of the story I guess is that while we can easily swap between data types in ColdFusion, once we have to interact with the outside world, we have to be really careful how we define our data. To the outside world, an XML object is NOT the same thing as the string representation of an XML object. It's actually not the same thing in ColdFusion either, but, due to run-time automatic data conversions of a typeless language, we rarely have to worry about it.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




Reader Comments

Jun 15, 2009 at 1:26 PM // reply »
19 Comments

If I replace your cfsavecontent with this:

<cfxml variable="strData">
<data>
<value>Test</value>
</data>
</cfxml>

I get the same error, and it is definitely a XML object being passed.


Jun 15, 2009 at 1:29 PM // reply »
7,572 Comments

@Stefan,

If you switch to CFXML, you have to remove the XmlParse() call. Then, it should work fine.


Jun 15, 2009 at 1:43 PM // reply »
19 Comments

Ah, that is true. But the data is still not considered being XML -
<cfreturn isXML(ARGUMENTS.Data)> returns 'NO' in the cfc, but when tested before being sent in, it says 'YES'. Some strangeness there.

(I put that in before the XmlSearch so I never actually got there)


Jun 15, 2009 at 1:58 PM // reply »
7,572 Comments

@Stefan,

Try IsXmlDoc(). It's meant for already-parsed documents.


Jun 15, 2009 at 3:00 PM // reply »
19 Comments

IsXmlDoc() also returns false. But using your original code, with cfsavecontent and type="xml", it works if you skip the XMLParse().

If I send in a CFXML created object and use type="any", isXML returns true, if i use type="xml", isXML returns false. If I skip XMLParse, the XMLSearch works in all cases, so it does not seem to need XMLParse()?. Seems very strange for me. XMLSearch() has no problem working with a xmlString instead of a xmlDoc.

I guess the bottom line is that you can use type="xml" as long as you do not do XMLParse on the argument before using it, because it turns it into an XML object automatically, regardless if you pass a XML string or a XMLDoc.


Jun 15, 2009 at 3:02 PM // reply »
7,572 Comments

@Stefan,

I believe XmlSearch() can take either an XML string or an XML document.


Jun 15, 2009 at 7:48 PM // reply »
19 Comments

Yes. But what I meant is that the error you got was because you tried to do XMLParse on something that was turned into a xml object when you set the type to XML. An argument of type xml can be an xml string or a xml object. So rather than changing the argument type to string, I think it is better to skip xmlParse.

The strange thing, as I see it, is when you invoke the webservice as a component, then it does not to parse it. On the contrary, it seem to un-parse it.

If you <cfreturn arguments.data /> from the cfc
and dump the return value, you will see a xmlDoc from the webservice and a XML string from the component, regardless if you send in a string or a xmlDoc.

To me, it seem like a bug that the XML object you send into a component is turned into a XML string. I would not expect that.

But I am easily confused :)


Jun 16, 2009 at 4:09 AM // reply »
8 Comments

WebService data types can be a pain in the ass. If you cast everything to a string you can always inside your own application cast them to the appropriate data type. Especially if you connect to other platforms the casting can be problematic, I've had troubles with .NET webservices vs. Coldfusion webservices (which are java thing) but obviously if everything are strings they can casted to the approriate data type.


Jun 16, 2009 at 8:32 AM // reply »
7,572 Comments

@Marko,

Yeah, strings are easy to parse back and forth. When it comes to SOAP, generally, I prefer to actually write the XML myself and pass that via CFHTTP so there are no surprises. I've just had trouble with complex type casting so many times in the past.


Jul 10, 2009 at 2:15 PM // reply »
3 Comments

Ben,
I'm trying to get the data from .asmx?wsdl
but all I see are the methods, just like your screen shot. I'm the consumer of web service so I can do anything with changing the datatype if they're using xml instead of string.
So how can I get my data? I've been searching anywhere with no success


Jul 10, 2009 at 3:15 PM // reply »
7,572 Comments

@Mega,

At the end of the day, SOAP is just an XML based standard. If you need to, you can create your own SOAP XML and post that using something like CFHTTP rather than trying to create a web service object. This will give you ultimate control over the way the data is passed. The WSDL file should define the overall XML data structure.


Mar 15, 2010 at 3:26 PM // reply »
5 Comments

can you show me a sample of calling your webservices using cfhttp. when i call it using cfhttp i get an error.

thanks


Mar 15, 2010 at 3:29 PM // reply »
7,572 Comments

@Charles,

What kind of data are you trying to post? I have a number of CFHTTP examples, some posting XML, some posting files; I also have some project stuff that will post just about anything (CFHTTPSession.cfc).


Mar 15, 2010 at 3:36 PM // reply »
5 Comments

i am posting xml, but posting anything will help also...

thanks
Charles


Mar 15, 2010 at 3:39 PM // reply »
7,572 Comments

@Charles,

Here is SOAP XML:

http://www.bennadel.com/blog/1809-Making-SOAP-Web-Service-Requests-With-ColdFusion-And-CFHTTP.htm

XML As a Form Field:

http://www.bennadel.com/blog/1420-Ask-Ben-Posting-XML-And-File-Data-With-ColdFusion-And-CFHttp.htm

XML as the Body:

http://www.bennadel.com/blog/745-Posting-XML-With-ColdFusion-CFHttp-And-CFHttpParam.htm

Hope that helps.


Mar 15, 2010 at 3:40 PM // reply »
5 Comments

thanks alot.


Mar 15, 2010 at 3:45 PM // reply »
7,572 Comments

@Charles,

No problem. If you have any issues with the given approach, just drop a comment in the appropriate blog entry.


Mar 15, 2010 at 4:06 PM // reply »
5 Comments

one more question...

when calling a cfc using http, how will i pass the method to call.

this is how i am trying to us this.

wsProcessRequestorXMLTest.cfc?wsdl

it this right or am i missing something?

Thanks
Charles


Mar 15, 2010 at 4:12 PM // reply »
7,572 Comments

@Charles,

When using CFHTTP, you probably won't need to use the WSDL stuff - that is only for SOAP. CFCs can be accessed via SOAP or REST. With SOAP, the method is declared as part of the XML packet.

To call via REST, remove the WSDL and just put the method as part of the Query string, or a URL CFHTTPParam.

<cfhttp url="myCFC.cfc?method=hello&foo=bar" />

... or:

<cfhttp url="myCFC.cfc">
<cfhttpparam type="url" name="method" value="hello" />
<cfhttpparam type="url" name="foo" value="bar" />
</cfhttp>

Does that help?


Mar 15, 2010 at 4:15 PM // reply »
5 Comments

yes this help.

thanks again.


Mar 15, 2010 at 4:16 PM // reply »
7,572 Comments

@Charles,

No problem :)


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 21, 2010 at 8:57 PM
The Bourne Ultimatum Starring Matt Damon And Julia Stiles
late to the party, but my observation is this: rewatch carefully for the platonic nature of the relationship between nicki and jason. she never flirts with him. he never comes on to her. they alway ... read »
Mar 21, 2010 at 7:40 PM
Is Simulating User-Input Events With jQuery Ever A Good Idea?
A couple of things. One you embed the initial state of of more-info in the CSS. IMHO, that behavior should be in jQuery: moreInfo.hide(); It shows that the behavior your toggling and closing is mor ... read »
Mar 21, 2010 at 3:59 PM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Elliott, according to Ben's experiment, serializeJSON() doesn't access the private data by default - it doesn't even access the getHair() method - so trying to clone a Girl.cfc via serializeJSON/des ... read »
Mar 21, 2010 at 3:49 PM
Ask Ben: Javascript String Replace Method
I'm confused a bit by what you are asking, but if had this sentence: The color, red, is in the style statement; style: red;. and wanted to remove all or change all of the commas, colons, and semi-c ... read »
Mar 21, 2010 at 3:13 PM
Ask Ben: Javascript String Replace Method
I am trying to make a java program to count the number of times that these punctuation marks occur in a body of text: , : ; . ! - ' " ? / \ I am using this piece to ferret out the commas: numcommas ... read »
Mar 21, 2010 at 11:13 AM
A New Wrist Pain
@chiropractor suwanee, Spoken like someone trying to sell something. Other than for minor, temporary relief from some back pain, chiropractic treatment is nothing but placebo effect and quackery. ... read »
Mar 21, 2010 at 6:32 AM
ColdFusion CFPOP - My First Look
Apologies... The field name in the db for C. is "BounceCode" It stores the code / message which is returned in the email. Sorry for the confusion. ... read »
Mar 21, 2010 at 6:29 AM
ColdFusion CFPOP - My First Look
@Jose Galdamez, Hi Ben and Jose 1st of all.. big thanks to Jose for his Skype chat a few weeks back. Your time was much appreciated. I have come up with a rather unelegant solution to my problem a ... read »