Ask a Jedi: Executing Code in OnRequestEnd after an Abort

A reader asks:

Why isn't application.cfc's OnRequestEnd guaranteed to be called like the "Global" class in .NET? I need to ensure a stateful var struct is wddx encoded into a client var at the end of a request. But it seems cfabort, cfthrow & cflocation all fail to save the data. The coldfusion documentation only mentions this happening with OnRequestEnd.cfm. What can I do?

So as you have found, any cfabort, cflocation, or cfthrow, will cause an immidiate end to the request. Code in both onRequest, after your cfinclude, or in onRequestEnd, will not run.

There isn't much you can do about that. Folks would argue that this makes sense, especially in the case of cfabort. Abort should abort. Period. That being said, there are some alternatives.

If your use of cfabort is meant to simply stop running more lines of code in the current page, but you still want the request as a whole to continue, don't use cfabort. Instead use a flag of some sort to let the rest of the code know not to run. This is actually what I normally do in forms. I'll have a showForm flag that will get set to false. I can then check for that and hide the form and print out a thank you message instead. Basically what I am saying is - rewrite your code a bit.

How about cfthrow? Well, like cfabort, cfthrow should stop everything. You could, if you wanted, in onRequest, wrap the cfinclude in try/catch. That works - but I'd urge against it as typically try/catch (imho) should be used to wrap small, atomic actions that can cause an error - not an entire request.

As for cflocation - you will have to rethink your approach. You may be able to use a flag again. You can write a custom tag that simply sets a flag. That flag could be checked in onRequest, or onRequestEnd, and a cflocation run from there.

Anyone else have thoughts on it?

Archived Comments

Comment 1 by Matt posted on 10/27/2005 at 6:35 PM

Yes, in Coldfusion 8.0, introduce a new Application.cfc function that doesn't abort even if a cfabort is present in the other parts of the template. I've myself had to resort to trys/catches to come up with a complex solution to a simple problem like this.

Let's call this function. OnRequestNotEnd ... :)

Comment 2 by Matt posted on 10/27/2005 at 6:38 PM

Or, introduce a new attribute to cfabort or cfexit, that only stops processing current template.

Comment 3 by quiksilv posted on 10/27/2005 at 6:51 PM

What you could do is include a file in you onRequestEnd file called 'end.cfm' (or better still #application.myEndRequestFileName#). Then before you cfabort include this file.

A bit of a hack i know but it should work?

Comment 4 by Brian Rinaldi posted on 10/27/2005 at 6:59 PM

cfexit will end the currently running page but still run your onRequestEnd (or anything in other templates). I have used this on occassion when I needed to do something like this. I it is supposed to be for custom tags, but I have found it will work just about anywhere.

Comment 5 by Brian posted on 10/27/2005 at 7:25 PM

The way I got around the cflocation issue in a recent application was to place a function called Redirect() in my utility component. Instead of calling cflocation, I call the Redirect() function which internally calls the same function(s) I call in OnRequestEnd() before performing the redirect using cflocation. You could probably apply similar solutions to the other tags.

Comment 6 by Raymond Camden posted on 10/27/2005 at 7:25 PM

Brian - what a good idea. I just did a quick test and it ran just fine.