A reader commented yesterday that my Application.cfc reference doesn't really say how to use the various methods. Since my reference is intended to be a simple code skeleton, I thought I'd quickly explain each of the methods and possible uses for them. Using my skeleton as a guide, let's cover the methods in order.
onApplicationStart
This method is run when the application starts up. Anything you want to define once in the life cycle of your application should be defined here. Typically this is where you will set your Application variables:
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.dsn = "empire">
<cfset application.foo = "some other variable">
<cfreturn true>
</cffunction>
onApplicationEnd
This method is run when the application ends. You could use it for logging. Frankly, I've never used it. It's nice that it is there and all, but I haven't had a practical need for it. Since every hit will reset the application time out, and applications only timeout after two hours, only a site with minimal traffic will ever even run this.
It is important to remember that you can cannot use the Application scope here. The application is over, remember? ColdFusion passes a copy of the Application scope to the method though and you can introspect that.
onMissingTemplate
Now this is a nice one. This method is run when a request for a CFM results in a file not found. ColdFusionBloggers.org uses this. For a full blog entry on it, see: onMissingTemplate Example
onRequestStart
This method is run before your request begins. You could use it to include a header, but I think this is a bad idea. I wouldn't mix display code inside your Application.cfc. Also - there may be cases where you don't want a header (like a CFM file that returns XML or JSON). You could use it to cfinclude a UDF library. Thing is - you don't have access to the Variables scope of your page here. So if you do use this method to include a UDF library, be sure to copy your UDFs into the request scope. That's something I like to do anyway since it allows me to call the UDFs from custom tags if I need them.
onRequest
AKA "that darn method that breaks CFCS" - onRequest is an odd one. It is run before your requested CFM actually runs, so in a way it is like onRequestStart, but onRequest actually represents the request itself. If you do not actually cfinclude the file that was requested, then nothing will be run. Because of this - you can't easily use onRequest with CFCs. (A bug I wish Adobe would fix.) A work around for this involves sniffing the type of request and actually deleting the methods on the fly (I believe Sean Corfield first described this method):
<cfif listlast(cgi.path_info,".") is "cfc">
<cfset StructDelete( THIS, "OnRequest" ) />
<cfset StructDelete(variables,"onRequest")/>
</cfif>
onRequest also has the interesting side effect of copying all the CFC methods into your local Variables scope of your CFC. Not a big deal, but don't be surprised if you cfdump the variables scope. Because of this - if you cfinclude a UDF library here, you don't need to copy them to the request scope.
onRequestEnd
This is run when the request ends. You may be tempted to do a footer here - but again, I'd recommend against it. Honestly, I've never found a real good use for this. You could use it to log a user's "path" through your system:
<cfif not structKeyExists(session, "path")>
<cfset session.path = arrayNew(1)>
</cfif>
<cfset arrayAppend(session.path, arguments.thePage)>
This could be useful for logging metrics. Then again - this same code could be used in onRequestStart.
onError
Run when errors occur, you should use this to handle errors for your sites gracefully. Way too many people don't use this and expose errors to your users. That's just plain wrong. It takes all of two seconds to send the error to yourself via email and show a simple "We're sorry" message to your users.
onSessionStart
Like onApplicationStart, you would put any code here that should only run once per a user's session. Any session variables that you want to exist should be set here.
<cffunction name="onSessionStart" returnType="boolean" output="false">
<cfset session.hits = 0>
<cfset session.name = "">
<cfreturn true>
</cffunction>
onSessionEnd
This is run when the session ends. Like onApplicationEnd, you can't directly access the user's session. You can, however, access a copy passed in as an argument. The Application scope is also passed in asn argument. Unlike onApplicationEnd, onSessionEnd can be very useful. It can help you determine what your user did last before his session expired. I wrote a whole blog entry on this you might find interesting: How ColdFusion can save your business!
I hope this helps. While writing I found another, even long, excellent article by Ben Nadel. His also goes into the variables you can set in Application.cfc: ColdFusion Application.cfc Tutorial And Application.cfc Reference
Archived Comments
Ray,
Thanks so much for the information. It really helped me understand how to use application.cfc, as well as give me an idea of what to include where.
I like onRequestEnd for logging based on the idea that anything not related to what gets displayed on the screen should be pushed off as late as possible so the page can start rendering for the user as soon as possible.
I like to cfflush the header and navigation of the page so that it starts to load while the main content is cooking in the CF engine. End users comment that the pages load faster, even though the total time is the same.
If you define onMissingTemplate() in a site's root application.cfc, and you define a MissingTemplate page in the CF Admin, which one takes precedence?
Ray,
You should put the How Cold Fusion can Save your business ecommerce example on CFlearn . I don't know how I missed it when you originally published it.
David, onMissingTemplate takes precedence, which is good. App should be able to override server in this case.
Ray,
Thanks for the nice explanation. Can you add this explanation as comments to your Application.cfc reference as it would help anyone downloading that PDF without looking at this post.
Regards
Qasim - actually - no. The point of the App.cfc file is to be more of a code skeleton. Something you can cut and paste into your file, or, what I did was make a Snippet out of it.
Do you have any considerations about what methods would NOT work in a FlashRemoting environment. I remember that there were issues with onRequest/onError giving a NULL result using FlashRemoting in CF7.
onError _will_ work with Flash Remoting. The code snippet I mentioned above should make flash remoting work as well as web services/CFCs.
Ray, you advise against include a page header/footer via onRequestStart and onRequestEnd...so, how *do* you recommend including those, if not via those methods in app.cfc ?
Check out:
http://www.coldfusionjedi.c...
Hey Ray,
Sorry to drag up an old thread,, just wondered...
I have been using a standard Application.cfc based on your template for a while, but when i have tried to use cfajaxproxy it generates an error if i have anything in onRequestStart.. if i delete that, although it breaks my site atm the cfajaxproxy stuff works fine.
Any ideas why this might happen?
onRequest. You will need to remove it.
Thanks Ray,
Why is this? is it a bug or is it like my bugs, actually a feature ;)
Officially it isn't a bug. When you have onRequest, it blocks all Web Service or CFC method hits. This is documented. You _can_ get around it using a trick in onRequestStart. I don't have the trick handy (Sean created it). Personally I consider this a bug and I wish Adobe would change it.
Thanks very much for the responce :)
It is annoying I suppose, but it was no great problem deleting onRequest!
I can finally sit back with a beer and enjoy my added Ajax functionality.
Thanks again, and keep blogging.
Thumbs up from me in the UK!
So the question is - what type of beer?
Oh, only the best Lager!
Carling, or maybe a refreshing Magners Cider!
Whats your tipple of choice?
Hmm. Not sure I have a favorite. Used to be Killian's Red, but I'm a bit over that now. I like dark, rich beers, that are strong.
You'd love 6X its something we have here - not sure if you have it there... velvety smooth!
Ray,
You mentioned if you include your UDF library in the onRequestStart method, that you need to copy them to the request scope in order for them to be available on all pages.
I understand using onRequest to include it will do that automatically for you, but how are you copying a UDF library to the request scope?
Thanks
I do it by hand. You can treat UDFs as variables.
<cfset request.foo = foo>
That will copy foo, whether it be UDF, array, whatever, to the request scope.
So in your onRequestStart, you include the UDFLibrary, and if the library contained 5 functions, right after the include you would have 5 set statements, 1 for each function?
Thanks,
Dan
Nope - I do it all in the include. That keeps my app.cfc simpler.
Ray,
I use Flex on my corporate intranet. I have previously written a meeting scheduler with Coldfusion 7 (tested on 8 and works as is). I enable session management and use a SESSION.DataSourceName in the onSessionStart function in my application.cfc so all components will reference same datasource. While this is fine with my CF pages, I get an error when I call the CFC from a Flex remote object, "[RPC Fault faultString="Unable to invoke CFC - The requested scope session has not been enabled." faultCode="Server.Processing" faultDetail="Before session variables can be used, the session state management system must be enabled using the cfapplication tag."]" Any idea how to make this work?
Ray,
I used to email myself a dump of the errors, but i got so many that I couldn't keep up with them all because of the large volume of traffic running through my sites.
Also, sending mail in coldfusion 7 is a memory hog - so much so that I ended up writing my own cf_mail custom tag and a python script to send the mail as a separate process.
I also wrote my own fatalError(message) function that looks at my isDebugging() function and will dump out all the scopes I need when I'm fixing things. Otherwise fatalError() will just show the simple message to the user.
I found this method to be much more useful than emailing myself an endless pile of errors I'd never read.
I'd love to hear your thoughts on my methods. I still have a nagging feeling that I should be doing more, but as far as time management goes, I'm doing the best I know how currently.
I'm surprised by your statement about mail in CF7 being a hog. I know one of the big improvements to CF7 was the speed of mail. I've never seen it be a hog myself.
As for your method, sure, I mean, when in development you want to see the error immediately, and then hide it when in production. That's typically recommended I'd say.
Hi Ray,
This is such an old topic that I'm afraid you might not even get this, but I'm still not clear on how you include UDFs in application.cfc. Here's my code snippet:
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<!--- UDFs to include --->
<cfinclude template="/udf/listToQuery.cfm">
<cfif IsDefined("Form.logout")>
<cflogout>
</cfif>
You wrote:
Nope - I do it all in the include. That keeps my app.cfc simpler.
So are you saying I should include a statement in the UDF itself? How would I do this for this example UDF, listToQuery.cfm?
Thanks!
- Sung
Ugh...never mind. I was putting the chunk into the wrong component section! Now that I put it in OnRequest(), it works beautifully.
Please be aware that using onRequest has side effects. Search the blog here to see what I mean. (Although somewhat fixed in ColdFusion 9.)
Thanks, Ray. I think I finally figured it all out -- took a while. It involved using cf_copyUdfs custom tag (http://www.electricsheep.co.... I'm no longer using the onRequest method:
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<!--- UDFs to include --->
<cfinclude template="/udf/listToQuery.cfm">
<cfinclude template="/udf/QuerySim.cfm">
<cf_copyUdfs>
Now that the UDFs are copied to the variable scope, I have access to them anywhere. That did it!
- Sung
Glad you got it working. Typically what I do for udf libraries is just create a component for them, like utils. I then create an instance in the app scope and do application.utils.foo(). It is a bit more typing though. Luckily Model-Glue has a nice way to make this simpler.
Hi,
For better or worse, I have some includes that I want to include, but I want to switch to a cfc and I have some ajax-called functions in a cfc that still need to work. Rather than re-write all my code, I was trying to use the hack recommended by Sean Corfield.
Raymond's post was the first I came when trying to fix this and I really appreciate all the helpful information here. However, the hack he proposes wouldn't work for me. Instead I had to change the if statement to use the arguments.targetPage:
<cfif right(arguments.targetPage,4) is ".cfc">
<cfset StructDelete(variables,"onRequest")/>
<cfset StructDelete( THIS, "OnRequest" ) />
</cfif>
I got this piece from Sean's site. I was surprised it made a difference, but it did. Thanks to both sites!! Hopefully this will save someone else some research time.
Would you put variables that determine if a user is logged in our out in the ApplicationStart or SessionStart? I would think that you would want it in the ApplicationStart as you would want to see that a user is not logged in? (The variable would equal false or 0...)
You would want it onSessionStart. It is user specific and should be set when the user first hits the site. onApplicationStart would not be run if the application is already started.
Hi,
Normally in which scope we should put our data source(Application,Session,Request)?Or it depends what kind of data source we are using.
Almost always a datasource is an application variable. It is rare for an app to use a datasource based on a particular user.