Handling ColdFusion Custom Exceptions In Flex

Introduction

There may be occasions when a CFC function being used by Flex needs to throw a custom exception to alert the caller of the function that some problem has occurred during the function (1). If you're using Flex to call a CFC function that may throw an exception then you need a way to handle the exception in Flex (6) and display an appropriate error message to the user. This blog entry desribe a technique I use to throw an exception from a CFC function and then display an exception message in Flex to the user. Flex automatically translates the attributes of the ColdFusion cfthrow tag (3) to property values of the Flex Fault class (8).

Details

ColdFusion provides the cfthrow tag (2), which has several attributes that you can use to provide information about the exception being thrown. You can use the message attribute to provide a brief description of the problem, the detail attribute to provide a more detailed description, the type attribute to indicate a specific custom exception type, and the errorCode attribute to specify a error number that corresponds to the problem.

For example:



<cfthrow type="CreditCardException.AuthorizationNotAvaialable" errorcode="9"
detail="Could not connect to the credit card authorization site. Please try again later.
The system administrator has been notified about the problem."

message="Credit card verification site unavailable."
/>


When using the mx:RemoteObject tag (4,5) in Flex to call a ColdFusion CFC you can specify an ActionScript function to be called should the CFC generate an exception (6). For example:



<mx:RemoteObject
id="CreditCardSale"
destination="ColdFusion"
source="coldspring.examples.JustColdSpring.HandleCFCException.bin-debug.components.CreditCardSale"
showBusyCursor="true" >


<mx:method name="processCreditCard"
result="resultProcessCreditCard(event)"
fault="faultProcessCreditCard(event)"/>



</mx:RemoteObject>

If the processCreditCard method generates an exception, Flex will automatically call the function specified as the value for the mx:method tag's fault attribute. In the above example, that function called will be the faultProcessCreditCard function. Flex will pass to this function an object of type FaultEvent (7). The FaultEvent object has a public property named fault, which is of type Fault (8). The Fault class (8) has several properties that will be populated with values from the exception thrown by the CFC function. This table shows which attribute of the ColdFusion cfthrow tag is used to provide the value for which Flex Fault property.

cfthrow attribute Flex Fault property
errorCode faultCode
message faultString
detail faultDetail

One thing to note is that Flex will add to the message attribute's value the text "Unable to invoke CFC". So a cfthrow tag's message attribute with a value of "Credit card verification site unavailable" will become "Unable to invoke CFC - Credit card verification site unavailable" in the faultString property. Thus the faultString property value isn't one you probably want to display to the user of your Flex application.

Usually, I give the cfthrow's detail attribute a value that will be the explanation of the problem I want the user to see in my Flex application. Then in the function of my Flex application that was specified to handle the exception (eg, faultProcessCreditCard function) I use the Alert control to show the user the value of the faultDetail property. For example:



Alert.show(event.fault.faultDetail,"An Error Has Occurred" );

Another technique I've used is to change the state of the Flex application and display the value of the faultDetail property as a part of a mx:Text component. See reference 9 for an example of this technique.

One important point is that all exceptions generated by calling the CFC function will be handled by calling the same Flex function. If the CFC function needs to throw different types of exceptions, then you could use multiple cfthrow tags. If you give each cfthrow tag its own errorCode value, you can then use logic within the Flex function to do different actions depending on the value of the Fault class faultCode property.

You can view a complete example of handling in Flex an exception generated by a CFC function (10). Right click on the Flex application and select view source to see the source code.

References

  1. Handling Errors, ColdFusion Developer's Guide
  2. Using the cfthrow tag, ColdFusion Developer's Guide
  3. cfthrow, CFML Reference
  4. Using RemoteObject Components, Data Access and Interconnectivity
  5. RemoteObject, Adobe Flex 3 Language Reference
  6. Handling Service Results, Data Access and Interconnectivity
  7. FaultEvent, Adobe Flex 3 Language Reference
  8. Fault, Adobe Flex 3 Language Reference
  9. Handle Registration Errors, Bruce Phillips' Blog
  10. Handle CFC Exception Example

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Do you know why CF 8.0.1 produces this output as observed by ServiceCapture:
faultDetail (String): For details, turn on Robust Exception Information in the ColdFusion Administrator
faultString (String): Unable to invoke CFC - Credit card verification site unavailable.
faultCode (String): 9

Notice the faultDetail is not what it should be. I know that I can enable this feature in CFAdmin, but on a production server debugging is not enabled. So what looks to be a friendly error message in development turns into "For details..." when uploaded to a server with robust exception handling disabled.
# Posted By Mike Chabot | 5/9/08 9:08 PM
Mike - thanks for the comment. You raise a great point. I tested this code on my both development server and on my live server and it worked the same each time. My live server is a hosted one (CrystalTech.com) so I didn't think about the debugging settings in CF Admin effecting the result returned to the Flex application.

However, you're right. When I uncheck Enable Robust Exception Information in CF Admin on my development server I get the same results as you. My production server on CrystalTech.com must have enabled Robust Exception Handling. But they don't have "Enable Request Debugging Output" checked because I don't see the general debug information, etc on my test CFC page on my live server.

One quick solution would be to use the faultString property instead of the faultDetail property. You could parse out the "Unable to Invoke CFC" part of the string before displaying its results to the user. Since the faultString's value comes from the message attribute of the CFThrow tag you could use the message attribute to provide more of a user friendly message.

Again - thanks for the comment.

Bruce
# Posted By Bruce | 5/10/08 7:07 AM
Although you use the number 9 in your example, the error code attribute and corresponding faultCode value can store any string, and this value seems to pass to Flex unmodified by CF. So an alternate strategy would be to have "CreditCardException.AuthorizationNotAvailable" as the error code and to handle this error code value inside of Flex. The error message that gets displayed would be defined in Flex instead of being sent directly from the server, to deal with the situation of CF altering the error details it sends out.
# Posted By Mike Chabot | 5/10/08 8:55 AM
Doesn't seem to work when invoking a cfc as webservice :(
Every cfthrow seems to be transformed in some predefiend Fault object and all the details specified in the cfc are lost.
Something like this (hope it doesn't get messed up when submitting this):

(mx.rpc::Fault)#0
errorID = 0
faultCode = "Server.Error.Request"
faultDetail = "Error: [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032: Streamfout. URL: path/to/cfc"]. URL: path/to/cfc"
faultString = "HTTP request error"
message = "faultCode:Server.Error.Request faultString:'HTTP request error' faultDetail: name = "Error" rootCause = (flash.events::IOErrorEvent)#1
bubbles = false
cancelable = false
currentTarget = (flash.net::URLLoader)#2
bytesLoaded = 0
bytesTotal = 0
data = ""
dataFormat = "text"
eventPhase = 2
target = (flash.net::URLLoader)#2
text = "Error #2032: Streamferror. URL: path/to/cfc"
type = "ioError"

Been trying for hours to get this to work, but not getting anywhere.
Works fine using RemoteObject, not with WebService.
# Posted By Muzak | 11/4/08 9:11 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner