The title kind of says it all. Most people have heard, or unfortunately ran into, the issue with Application.cfc and onRequest when used for Ajax or Flash Remoting calls. It just plain doesn't work. You don't get a nice error either and if you haven't heard of this bug, your going to be quite confused.
The good news is that ColdFusion 9 completely fixes this. Want to use onRequest and still work with CFCs? No problem. An Ajax/Flash Remoting/Web Service call to a CFC within a directory using onRequest will simply ignore the method! Consider this simple example using a new script based Application.cfc:
component {
this.name="FixToOnRequest";
public boolean function onRequestStart(string target) {
writeLog(file="cfcfix",text="Running onRequestStart for #arguments.target#");
return true;
}
public boolean function onRequest(string target) {
writeLog(file="cfcfix",text="Running onRequest for #arguments.target#");
include arguments.target;
return true;
}
}
My APplication.cfc has 2 methods, onRequestStart and onRequest. In both, I write to a log file. I then whipped up test.cfm:
This is test.cfm.
and test.cfc:
component {
remote string function sayHello() { return "Hello World"; }
}
I requested both in the browser. In the case of test.cfm, I got:
"Information","web-15","07/13/09","06:46:21","FIXTOONREQUEST","Running onRequestStart for /test.cfm"
"Information","web-15","07/13/09","06:46:21","FIXTOONREQUEST","Running onRequest for /test.cfm"
For my CFC, I got:
"Running onRequestStart for /test.cfc"
Notice that onRequest didn't run at all.
ColdFusion 9 also adds onCFCRequest. This works very much the same way as onRequest. It gives you complete control over the CFC request. If you don't actually run the method yourself, then, well, it isn't run. Much like how onRequest forces you to really include the file.
onCFCRequest is sent three arguments: CFC Name, CFC Method, and a structure of arguments. Invoking a dynamic CFC and method is a bit tricky in an all script CFC. This is how I did it, but I'm willing to bet there is a simpler way:
public boolean function onCFCRequest(string cfc, string method, struct args) {
writeLog(file="cfcfix",text="Running onCFCRequest for #arguments.cfc#, method #arguments.method#, args: #structKeyList(arguments.args)#");
var comp = createObject("component", arguments.cfc);
var res = evaluate("comp.#arguments.method#(argumentCollection=arguments.args)");
if(isDefined("res")) writeOutput(res);
return true;
}
The method creates an instance of the component first. Note that my var scope is the second line of the method and after a logging call - this is new to ColdFusion 9. I use evaluate to call the method on the CFC, and then use isDefined as a workaround for checking for a null response. Not the most elegant code, but it works. If I go to:
http://localhost:8501/test.cfc?method=sayhello&foo=1&zoo=2
I get this in my log:
"Running onCFCRequest for test, method sayhello, args: zoo,foo"
I'll be honest - even without the onRequest bug, I didn't use it very often. Now that it's fixed though I won't feel so inclined to avoid it. onCFCRequest could be very useful for logging requests to an API and seeing which methods get used more often.
Archived Comments
"Notice that onRequestStart didn't run at all. "
You mean onRequest didn't run at all.
Fixed.
Does anyone know if CF9 fixes the nasty leading zeros issue that affects the cf ajax grids?
Where you have 009 stored in the db but the grid displays 9?
@Ray - I know that you've blogged on this in CF8 but I'm just curious as to whether or not this is going to be a non-issue going forward.
Looks like no. :(
<cfset s = "009">
<cfoutput>#serializeJSON(s)#</cfoutput>
Still returns 9.0.
does onCFCRequest work with webservices & Ajax or does it break them?
It should work just fine. I have not tested with web services though. You would be responsible for returning the proper XML response which would be a bit cumbersome.
I dont understand what's the attraction with script based cfcs. What is different from the more conventional tag based cfcs apart from what you have to type at the keyboard?
Is there any functional or speed difference? Why are you so fixed on script based cfcs?
I notice a lot of the ajax examples use script based cfcs - is there a reason for that or is it just that it looks more like "real" programming and tag-based cfcs look more like "toy" programming?
For many programmers in other languages, script is the _only_ way to write code. Therefore, script based CFCs are more familiar to them and easier to pick up.
For me, I've got a lot of experience with CF as a tag based language, and a lot of experience with Flex and JS. Flex too has a mix of tags and script, but your logic is all done in script.
For me, having used both, I prefer script. I can write logic _much_ quicker in script than in tags. (Note that I keep saying 'write logic' - so I'm not talking about front end views, but specifically business logic type code.)
At the end of the day, it has nothing to do with 'real' versus 'toy', but simply productivity. I'm more productive in script when writing logic. Therefore - I use it. I also believe it is inherently quicker for that situation - therefore I promote it. Just as much as I'd recommend tags for outputting dynamic HTML.
Hi Ray,
I recently rolled out a mirrored application. One server is on CF9 and the other is on CF8. I ran into this problem on the CF8 box, but I ran into a different problem on the CF9 box after I rolled out the fix.
I'm noticing that the onRequest does not fire/error when calling a CFC in CF9, and CF8 needs this fix in order to work. I'm finding, however, that CF9 still fires onRequestEnd if you use onRequest. Is this intended?
-Mike
I rarely use onRequestEnd so I have no idea. If you are seeing it run, then, I guess it is expected. Frankly, I've -never- seen onRequestEnd in the wild.
If you want it to not do something on a CFC call, just check the request url and if it ends in .cfc, don't do anything.