Ok, so I love Application Events and the new Application.cfc. I really, really love it. That being said, there are a few "issues" you should be aware of when using it:
onError: When using the onError method, every single <cflocation> call will fire the event. Kind of a silly bug, but it didn't get found till too late. Christian Cantrell came up with a nice work around to place inside your onError:
<cfreturn/>
</cfif>
If you don't have this, your error handling will fire when you don't really want it to.
onRequest: This is covered in the docs - but I know people are going to miss it. If you use onRequest, you cannot use Flash Remoting or Web Services. This is kinda silly too and I hope it gets fixed soon. I get the reasons behind it, but it should still be corrected I think. Sean came up with a nice workaround for it. If your CFCs are in a subfolder, add a Application.cfc in and use code like so:
<cfset structDelete(variables,"onRequest")/>
<cfset structDelete(this,"onRequest")/>
</cfcomponent>
Archived Comments
I posted this in the Macr forums, but no response. When I add this code to my onError function, I now get an error saying rootCause is not defined in the exception argument. When I dump the exception argument, all I see is a TagContext. So I still get all the errors from CFLOCATION tags.
Any ideas?
You should probably check to see if rootcause exists in the exception struct.
So,
cfif structkeyexists(arguments.exception,"rootCause") and .....
Yes, I do that--which is great but it still doesnt help with the cflocation auto-triggering the onError function. All my cflocation tags trigger this, and the fix for the rootCause checking doesnt help me. Any pointers?
odd - I don't seem to remember seeing cflocation triggering onerror. You sure you aren't using a beta?
Anyway - why not simply cfdump the exception and see if it is obvious what the exception is.
Your blog entry even says cflocation will trigger the error--and it does indeed.
I am running a full version of MX7 with the second hotfix.
I added a CFDUMP of the exception structure in my onError tag. Turns out in your blog you say to use rootCause, but that doesnt exist. What does exist is "Type". So the example code in your entry should be this:
<cfif StructKeyExists(arguments.exception,"type") and arguments.exception.type eq "coldfusion.runtime.AbortException">
<cfreturn/>
</cfif>
Thanks for helping me lead to the right answer.
Yes, you are right - sorry for that. I'll try to update the entry a bit later today!
Tim,
When I try the code you just posted I receive this error:
Element EXCEPTION is undefined in ARGUMENTS
I assume you are not receiving this error message, so I wonder what I could be doing wrong.
Here is the whole content of my onError function:
<cffunction name="onError">
<cfargument name="Exception" required=true/>
<cfargument type="String" name="EventName" required=true/>
<cfif StructKeyExists(arguments.exception,"type") and arguments.exception.type eq "coldfusion.runtime.AbortException">
<cfreturn/>
</cfif>
... code to display error message to user...
</cffunction>
You guys are my hero. I am completely embracing the new application.cfc method. My only other beef so far is that, when I was using the 'cflogin' method of maintaining authentication, code that I put in 'onSessionEnd' would never properly execute a 'cflogout'. I ended up maintaining user log-in state in an application.array and simply removing them onSessionEnd. Otherwise, my users would always get 'you are already logged in' every time they walked away and came back to their desks after the session timeout. Oh well, there are too many advantages to using the application.cfc to quibble over small stuff.
Quick question: Does anyone else here include template-style code in the onRequest block? I have a cfinclude of all header style code right before my cfinclude of #argument.thePage#.
Justice - If you have tied your security to session with loginstore=session, then this makes sense. In onSessionEnd, the session is already dead, therefore cflogout has no purpose. You can just ignore it. Just noticed you said they get 'already logged in' messages. Try adding loginstorage="session" (in the This scope, like other settings) and see if that helps.
I do NOT do layout in onRequest.
Well, for whatever reason (even tho I have loginstorage set to session) I would still have to re-start the server to allow a user to log back in. I must have something mucked up somewhere =)
Is there a reason you do not do any other code in onRequest? ie, I have an include that just has my CSS links, and 2 javascript references in it. What would be the difference in putting this in an include on each page? I used to do this in my application.cfm file. Where should it go when using application.cfc?
I'll double check the session/onsessionend/cflogon thing today, cuz that definitely sounds wrong.
I rarely use onRequest since it impacts web services and flash remoting. That being said, I do layout in a custom tag. If you did it in onRequest, it would mean EVERY page would you use the layout, which would be a problem if your site had popups, or if you wanted something different before a person was logged in.
This code I inherited uses onRequest. I want to use AJAX and this is preventing it. I tried the sep app.cfc trick, but no go, or I am doing it wrong. the whole app.cfc is new to me.
So how do I remove this w/o errors?
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true">
<cfinclude template="#arguments.thePage#">
</cffunction>
Just remove it. Your onRequest is doing nothing (technically it is doing something, but functionally it is not), so just remove that onRequest method and see if it helps.
I tried that, but get an error that it can't find a UDF.
If your page is trying to load a UDF, then you need to cfinclude it. One thing people use onRequest for is to load UDFs into the variables scope. Perhaps your onRequest had it? The one you had pasted did NOT do that.
The udfs are getting loaded on the onRequestStart
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfscript>
if(NOT IsDefined("Application.Init") OR IsDefined("URL.ReInit")){
// init the bookiecharts cfc
Temp = createObject("component","bookiecharts.cfcs.settings").InitApplication();
//Set Global Init app flag var to true
Application.Init = true;
}
</cfscript>
<!--- Call the FormURL2Attributes tag --->
<cfmodule template="/#Application.Settings.RootMapping#/customtags/FormURL2Attributes.cfm">
<cfinclude template="/#Application.Settings.RootMapping#/udfs/udfs.cfm">
<cfsetting showdebugoutput="yes">
<cfreturn true>
</cffunction>
I'm not sure what to tell you then. Commenting out the onRequest should not have c... ohhh. Ok, so if I remember right, the presense of onRequest has the side effect of copying the variables from the CFC to your page's Variables scope.
THe problem you have is that onRequestStart is using it's OWN variables scope now. So your page doesn't have access to the UDFs. What you need to do, or what you CAN do I should say, is consider simply copying the UDFs to the request scope. Then you change any call like so, result = someUDF(), to: result = request.udfs.someUDF().
cool, that worked. Now to tackle my ajax.cfc issue. :(
Thanks Ray, that just helped me after 30 minutes of beating my head against the wall :)
Example in blog is still incorrect. Examples for onError seems to be incorrect everywhere, including on the LiveDocs. Where do this 'rootCause' come from? An early beta? It does not exist in my exceptions anyway, that's for sure.
Happy new year,
It does exist - just not always. The code should be updated to _first_ check for the existence, and THEN check the value.
Ok, found it... but in my tests rootCause contains the original error struct, like arguments.exception.rootCause.type etc and therefore you would also need to check if arguments.exception.rootCause is a simple value?
Actually, I can not get a onError triggered by cflocation at all. I tried:
<cffunction name="onError" returnType="void">
<cfargument name="Exception" required=true/>
<cfargument name="EventName" type="String" required=true/>
<cflog text="onError triggered" file="RedirLog">
</cffunction>
But it does not react at all on my cflocations. Any tip of how I should detect cflocation?
To be honest, I seem to remember issues with cflocation AND cfabort, and the behavior changing from 7 to 7.0.2. It may even be totally fixed in 7.0.2 which may explain why you can't reproduce it. One quick tip - you can always wrap a cfdump of the arguments in onerror inside a cfsavecontent and save the result to a file. Or cfdump the arguments and then cfabort.
hi guys
i previously use cferror on Application.cfc/cfm. i found tat the '#ERROR.Diagnostics#' able to tells exactly which line of my code occurred.
does onError function has this feature as well? and how?
What you get in onError is the same as cferror. Actually a bit more as if the error occurs in another method of the app.cfc file, you get that info as well.
Hi All,
I have some code in the onrequeststart() function which checks to see if a user is logged in, in order to access certain admin pages.
Now if they are not logged in, it would move them to the login page.
Here is a snippet of the code found in the onrequeststart function.
<cfheader statuscode="301" statustext="Moved Permanently">
<cfheader name="Admin login" value="localhost/admin/index.cfm">
<cfabort>
However, the move never happens.
It goes to the onerror() ( i added the code from this blog) and all it does now is show an empty page.
Any help here guys?
Add a dump in onError and see what it is. Oh - it also may be abort. CFABORT will run onError. You can add a check in OnError to see if it was cfabort, and if so, ignore it.
<cfif arguments.exception.rootcause.type is "coldfusion.runtime.AbortException">
<cfreturn>
</cfif>
For googlers like me looking for answers...
Just wanted to pass along the combination of the two methods used in this thread for trapping the cfabort/cflocation on error bug. netheir one of the methods worked completely for me but when I combined both all is well.
<cfif isDefined("arguments.exception.Type") and (arguments.exception.Type eq "coldfusion.runtime.AbortException")>
<cfreturn/>
<cfelseif isDefined("arguments.exception.Type") and (arguments.exception.Type eq "Expression")>
<cfif isDefined("arguments.exception.RootCause.Type") and arguments.exception.RootCause.Type eq "coldfusion.runtime.AbortException">
<cfreturn/>
</cfif>
</cfif>
Thanks Jim.
I noticed this is an old blog, but i thought i would post that I have another work around to the onRequest issue. I have blogged about it here. http://www.personal.psu.edu...
It basically shows how the code needs to invoke the method requested when ajax/webservices are being called.
Just wanted to say we are still on CF7 (yup) and we had this prob too. Your solution works great.
Is this fixed in CF8? -- or does this bug still persist?
onError was fixed a while ago.
onRequest blocking flashremoting/CFC calls was fixed in CF9.