ColdFusion Application.cfc Tutorial And Application.cfc Reference

Posted May 25, 2007 at 7:22 AM

Tags: ColdFusion

I sometimes do in-house presentations here at Nylon Technology. Last night, I was asked to prepare "something" for this morning. In a mad rush, I threw together this presentation on ColdFusion's Application.cfc component. I am sure most of you have seen this stuff before, and a lot of it is right in the ColdFusion documentation, but for some people at my office, this will be new stuff. I am covering things like Application.cfc events, variables, and some tips and tricks that might not be obvious.

I finished working on this last night at like 9:30 so you better believe I did NOT, nor do I care to proof read this :) It's advertised strickly "as is."


ColdFusion Application.cfc Tutorial For Nylon Technology

ColdFusion MX 7 introduced the Application.cfc ColdFusion component. This component replaces the traditional Application.cfm and OnRequestEnd.cfm ColdFusion application templates. Furthermore, if Application.cfc is present, both of these templates are ignored by the application.

In addition to replacing the request start/end functionality of the old application templates, Application.cfc provides hooks into many additional application level events including:

OnApplicationStart()

This fires when the application first runs. It is a single-threaded method call.

OnSessionStart()

This fires when an individual session first runs. It is a single-threaded method call.

OnRequestStart()

This fires when a page request first runs. It is a single-threaded method call.

OnRequest()

This fires when the requested template needs to get processed.

OnRequestEnd()

This fires at the end of every page request. It is a single-threaded method call.

OnSessionEnd()

This fires at the end of every session. This will fire either for a session timeout or if the server is shutting down. It is a single-threaded method call.

OnApplicationEnd()

This fires at the end of the application. This will fire for an application timeout of if the server is shutting down. It is a single-threaded method call.

OnError()

This fires if an exception gets thrown and is not caught by the controlling code.

All of the above methods are optional. You have an Application.cfc that is completely empty. Also, I say that the above methods are single-threaded which means that you do not have to worry about locking the code within them. However, any and all of these methods can be called explicitly by other parts of the application (ex. calling OnApplicationStart() from OnRequestStart() for manually fired application re-initialization). In this case, the manually invoked events are NOT single-threaded and may be open to race conditions.

In addition to application event hooks, Application.cfc provides public properties that define the application in a manner similar to the CFApplication tag. The following are available THIS-scoped properties:

THIS.Name

This is the name of the application and is used to tie a request to existing application memory scopes.

THIS.ApplicationTimeout

The time span an application will exist before it times out (if the application is not accessed in any way). This defaults to the value set in the ColdFusion administrator.

THIS.SessionManagement

A boolean flag to determine if the SESSION scope should be used. This defaults to false.

THIS.SessionTimeout

The time span a session will exist before it times out (if the application is not access in any way by that session's user). This defaults to the value set in the ColdFusion administrator.

THIS.SetClientCookies

A boolean flag to determine if the CFID and CFTOKEN values are sent as cookies to the client's browser. This defaults to true.

THIS.SetDomainCookies

A boolean flag to determine if the CFID and CFTOKEN values are set for domain and not just a host value. This defaults to false. I have never used this and so I am not exactly sure what this means.

THIS.ClientManagement

A boolean flag to determine if the CLIENT scope should be used. This defaults to the value set in the ColdFusion administrator.

THIS.ClientStorage

If client management is being used, this determines where the client variables are being stored (cooke, registry, or database). This defaults to the value set in the ColdFusion administrator.

THIS.LoginStorage

The place login information is stored (cookie or session). I have never used this, so I am not exactly sure what that means. Defaults to cookie.

THIS.ScriptProtect

A boolean flag to determine if the variables will be protected from cross-site-scripting attacks. Again, I have never used this and I am not sure what it does. This defaults to the value set in the ColdFusion administrator.

Putting it all together, an Application.cfc ColdFusion component skeleton would look something like this:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="Application"
  • output="true"
  • hint="Handle the application.">
  •  
  •  
  • <!--- Set up the application. --->
  • <cfset THIS.Name = "AppCFC" />
  • <cfset THIS.ApplicationTimeout = CreateTimeSpan( 0, 0, 1, 0 ) />
  • <cfset THIS.SessionManagement = true />
  • <cfset THIS.SetClientCookies = false />
  •  
  •  
  • <!--- Define the page request properties. --->
  • <cfsetting
  • requesttimeout="20"
  • showdebugoutput="false"
  • enablecfoutputonly="false"
  • />
  •  
  •  
  • <cffunction
  • name="OnApplicationStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="Fires when the application is first created.">
  •  
  • <!--- Return out. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnSessionStart"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="Fires when the session is first created.">
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnRequestStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="Fires at first part of page processing.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="TargetPage"
  • type="string"
  • required="true"
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Fires after pre page processing is complete.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="TargetPage"
  • type="string"
  • required="true"
  • />
  •  
  • <!--- Include the requested page. --->
  • <cfinclude template="#ARGUMENTS.TargetPage#" />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnRequestEnd"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Fires after the page processing is complete.">
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnSessionEnd"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="Fires when the session is terminated.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="SessionScope"
  • type="struct"
  • required="true"
  • />
  •  
  • <cfargument
  • name="ApplicationScope"
  • type="struct"
  • required="false"
  • default="#StructNew()#"
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnApplicationEnd"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="Fires when the application is terminated.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="ApplicationScope"
  • type="struct"
  • required="false"
  • default="#StructNew()#"
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="OnError"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Fires when an exception occures that is not caught by a try/catch.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Exception"
  • type="any"
  • required="true"
  • />
  •  
  • <cfargument
  • name="EventName"
  • type="string"
  • required="false"
  • default=""
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

Now that we understand how all the events and variables are wired together, let's take a closer look at the individual application event methods.

OnApplicationStart()

This is the perfect place to define application-scoped variables (ex. APPLICATION.DSN for data source structures). If this method is invoked manually, be sure to call StructClear() on the APPLICATION scope before you re-initialize the data values. This will help to ensure a clean refresh.

The return boolean signals as to whether or not the application loaded successfully. Returning false will halt the processing of the rest of the events of the current page request.

OnSessionStart()

This is the perfect place to define session-scoped variables (ex. SESSION.Cart for eCommerce cart data). If this method is invoked manually, be sure to call StructClear() on the SESSION scope before you re-initialized the data values. HOWEVER! before clearing the scope, get a copy of the CFID/CFTOKEN values so that you can store them back into the session during re-initialization. ColdFusion will not automatically re-create these values as calling this event method is not actually restarting the session.

OnRequestStart()

This the perfect place to define request-specific and other request-scoped variables (ex. REQUEST.Attributes for the union of the FORM/URL scopes). This is also a good place to do universal FORM value scrubbing (such as removing smart quotes and trimming form field values).

If you application or sessions can handle manual re-initialization, this is a good place to check for those URL flags (ex. StructKeyExist( URL, "resetApp" )) and then manually invoke the OnApplicationStart() or OnSessionStart() application events.

If you are using the OnRequest() method and you expect this application to be used for flash remoting or CFC-based web service calls, this is the ideal time at which to check for the request type (standard page request vs. web service) and if need be, delete the OnRequest() method from the Application.cfc (ex. StructDelete( THIS, "OnRequest" )).

If the return value is false, the page processing will be halted.

OnRequest()

If you include this event then you must include the requested page via a CFInclude tag. The relative path of the template is passed as the only argument to this function. If you include the in this manner, the processed template becomes what is essentially a "Mix-In" of the Application.cfc meaning that it is actually part of the Application.cfc code. If you do this, the processed page will have access to the THIS and VARIABLES scope of the Application.cfc.

If the request page is included in this manner, it also means that the requested page will have access to all methods defined in the Application.cfc.

This is the perfect place to handle login management. Since this method determines which template gets executed, this is where you can check login status and conditionally include the login template rather than the requested template.

OnRequestEnd()

This is the perfect place to handle page logging. By doing it here (especially if the first command is a CFFlush tag), the user experience will not be affected by any processing overhead of this event method.

OnSessionEnd()

This is the perfect place to clean up sessions that have times out (ex. deleting uncommitted shopping cart information). This method does not have inherent access to the APPLICATION scope or the SESSION scope (as the OnRequestEnd() method has access to the REQUEST scope). In order to access those scopes, you must use the passed in arguments.

OnApplicationEnd()

This is the perfect place to log information about the application. This method does not have inherent access to the APPLICATION scope. In order to access that scope, you must used the passed in argument.

OnError()

This event gets called when an event fires and allows you to handle that error and include an error handling template if you so desire. However, this event cannot display anything to the user if the error occurs during the OnApplicationEnd() or OnSessionEnd() events as those are not request-related (unless called explicitly during a request).

One thing to be aware of (as of MX7) is that the CFLocation tag throws a runtime Abort exception (which makes sense if you understand that the CFLocation tag halts the page and flushes header information to the browser). As a work around to this, you can check the passed in Exception type and if its a Abort exception do not process the error:

 Launch code in new window » Download code as text file »

  • <cfif NOT CompareNoCase(
  • ARGUMENTS.Exception.RootCause.Type,
  • "coldfusion.runtime.AbortException"
  • )>
  •  
  • <!--- Do not process this error. Return out. --->
  • <cfreturn />
  • </cfif>

As a note of caution, if you use the OnError() event method to include a ColdFusion template that is also URL-accessible, you have to put in logic that knows not to use exception-related values if the template is access directly.

Additional Methods

The above event methods are those that the ColdFusion server will attempt to hook into during the application and page life cycle. Application.cfc is a ColdFusion component just like any other CFC file and because of that, there is nothing to stop you from defining as many methods in it that you want. One thing that I like to do sometimes is create a method CreateCFC() within the Application.cfc to provide short hand notation (and other benefits) not only to the other Application.cfc methods but also to any template that shares the Application.cfc memory scopes.

In addition to methods, you can create as many variables as you like within the Application.cfc memory scopes.

What Is A ColdFusion Application?

ColdFusion applications do not really exist. At least not in the way you might think of a traditional desktop application that has a running process. ColdFusion applications do not have a constant process. Instead, they have memory scopes. Each application has its own name which ties it to a chunk of memory somewhere. Every time you define an application through the Application.cfc (or CFApplication), what you are really doing it associating the current page request to the chunk of memory that is associated with that application name.

When you start to look at ColdFusion applications this way, it becomes a little more clear why you cannot explicitly kill an application or a session; there simply is nothing to kill. An application doesn't run unless you have a running page that requests to be associated with it.

When Does The Application.cfc Get Created?

It is important to understand that Application.cfc is newly instantiated for every single page request. This means that all the application settings and page request settings can be different for every page request. This information can be used to set up alternate session management configurations. For example, you might set THIS.SessionManagement to false for browsers that you know cannot accept cookies (and therefore cannot handle session management).

What If I Am In A Rush - Isn't CFApplication Easier To Code Than Application.cfc

This is absolutely not true. Remember, all of the information outlined in this presentation is completely optional. You don't have to have anything in your Application.cfc. For example, the following is a perfectly valid Application.cfc:

 Launch code in new window » Download code as text file »

  • <cfcomponent>
  • <cfset THIS.Name = "TinyApp" />
  • </cfcomponent>

Can you get any more simple than that? This is just as easy as the CFApplication tag, but if you go the Application.cfc route, you will have the advantage of being able to easily add in the other application event methods as you need them.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page





Reader Comments

Ian
May 25, 2007 at 8:17 AM // reply »
7 Comments

Thanks for the overview. I've got a couple of questions from trying to use Application.cfc.

First, do you set things in the application scope such as your datasource name and then do an application lock every time you need to call it? Or do you dump it into some other non-locking scope when you need it?

Second, when you run the onSessionStart() call, how do you get access to the variables that you create? For example, I have some queries that need to run only when a session starts but I want to cache them in some scope other than the session scope because they are called frequently and I prefer not to use all those locks. Or am I worrying about excessive locking for no reason?

For example, I would like to run this query:

<cfquery name="Request.getSystemSettings"
datasource="#request.ds#"
debug
cachedwithin="#CreateTimeSpan(1,0,0,0)#">
EXEC pr_getSystemSettings '#cgi.http_host#'
</cfquery>

onSessionStart() but I don't seem to have access to the query results outside of the cfc.


May 25, 2007 at 8:29 AM // reply »
235 Comments

"First, do you set things in the application scope such as your datasource name and then do an application lock every time you need to call it? Or do you dump it into some other non-locking scope when you need it?"

You do not need to lock variables set in onApplicationStart. CF single threads it for you.

Later on, if you want to read the values, then you do not need to lock them if they are simple constant variable (like DSN and most app variables.)

"Second, when you run the onSessionStart() call, how do you get access to the variables that you create? For example, I have some queries that need to run only when a session starts but I want to cache them in some scope other than the session scope because they are called frequently and I prefer not to use all those locks. Or am I worrying about excessive locking for no reason?"

You can access the Application scope in onSessionStart, but you would want to ensure you use cflock if you are updating the app scope.


May 25, 2007 at 8:49 AM // reply »
7,572 Comments

@Ian,

As Ray said, you do not need to lock the variable since OnApplicationStart() is inherently single-threaded. However, if you call OnApplicationStart() manually, then it is being called as if it were a regular, every day function:

<cffunction name="OnRequestStart">

<cfif SturctKeyExist( URL, "reset" )>
<cfset THIS.OnApplicationStart() />
</cfif>

</cffunction>

In this case, since we are manually trying to reset the application and not letting the ColdFusion application server call it when the app *starts*, then OnApplicaitonStart() is not single threaded.

Because I usually have something like this going on in my applications, I tend to put an APPLICATION-scoped CFLock in my OnApplicaitonStart() method. At the very least, it cannot hurt.

As far as the scopes to use, sorry about that - my presentation did not go into good detail about that - you would use the same scoping that you would in a traditional CFApplication / Application.cfm scenario:

<cfset APPLICATION.DSN = StructNew() />
<cfset APPLICATION.DSN.Source = "cool_db" />

<cfset SESSION.User = StructNew() />
<cfset SESSION.User.ID = 0 />

You can use APPLICAITON, SESSION, REQUEST, and all the other scope within the Application.cfc just as you would have with the Application.cfm (although not all are available in all the event methods).

As far as using the query results set in OnSessionStart() outside of the CFC, the problem here is that OnSessionStart() is not related to any given page request - it's a session-specific event.

If you want to create objects in an application-level event and then use them on the rest of the page processing, do that stuff in OnRequestStart() or even OnRequest().

And, like Ray said, as far as locking goes, if you are reading simple value, don't worry about locking. Locking has overhead and should only be used if you KNOW a race condition might occur (a race condition is that one thread might be reading a chunk of code while another thread might be trying to update variables within that chunk of code). If you know that NO other thread will ever update something like DSN values, then don't worry about locking.

Even if you are manually restarting the application (calling OnApplicationStart()), which could potentially cause a race condition, I would still say don't worry about it as that is a very small possibility and something that will happen only rarely.... and of course, evaluate the worst case scenario - let's say you are updating the DSN and some dude in Delaware gets a CF error cause he was trying to do a query just as you cleared the APPLICATION scope... and then he refreshes the page and it works... is getting rid of that chance WORTH the overhead of locking every single read of the DSN?


Ian
May 25, 2007 at 9:29 AM // reply »
7 Comments

So for the various query result sets and string values that don't change I can put them in the application scope and not worry about locking because nothing bad can happen?

What would you recommend for the query example I gave that should only be called when the session starts but because it is dynamic gets called on every page request? I can't really dump it to the session scope because the values are used on just about every page of the site.


Ian
May 25, 2007 at 10:01 AM // reply »
7 Comments

On a styling note, do you create the structures in your example so that it is easier to delete them later instead of having to reference each individual value?


May 25, 2007 at 10:15 AM // reply »
7,572 Comments

@Ian,

As far as the query goes, if it needs to be executed for every single page request, then put it in the OnRequestStart() event method. Since that method is called once per page request (unless called manually which I have never seen done), it is essentially single threaded and you will NOT have to worry about locking.

Scoping it directly into the REQUEST scope, as you have done, is valid, and is what I would do.

However, look at what it is doing... it is getting results based on the http_host value. This data, while it may change depending on the host, will NOT change across a user's page requests. In that case, I would put the query in the OnSessionStart() event method and scope it directly into the SESSION scope:

<cfquery name="SESSION.GetSystemSettings">...</cfquery>

Of course, you might take this even one step further; if this is going to be the same for a TON of people, no need to keep going back to the database right? Instead, in your OnSessionStart(), you can try to cache it in the APPLICATION scope:

<cffunction name="OnSessionStart">

<cfif NOT StructKeyExists( APPLICATION.SystemSettings, CGI.http_host )>

<cfquery name="qSystemSettings"></cfquery>

<cfset APPLICATION.SystemSettings[ CGI.http_host ] = qSystemSettings />

</cfif>

<cfset SESSION.SystemSettings = APPLICATION.SystemSettings[ CGI.http_host ] />

</cffunction>

What I am doing there is creating a system settings query object for each http_host that comes in and caching it in the APPLICATION scope. Then, for each session, I check to see if that setting object exists yet. If NOT, I created it and cached it. Then after that conditional check, I know that it exists and can then just get a reference to it in my session.

As far as using Structs vs. individual values, I like using structs cause I can logically group related data. This makes my code more readable (IMO) and also makes it easier to pass data; it's less code to pass a structure containing 10 values than to pass all 10 values.

Hope some of that helps.


May 25, 2007 at 11:12 AM // reply »
15 Comments

Hi Ben,

Yet another great overview. Thanks for the effort.

Could you make your web pages more print-friendly?


May 25, 2007 at 11:23 AM // reply »
7,572 Comments

@Will,

Glad it helped. I am going to work on making a print-friendly version of my blog detail pages. Thanks for bearing with me.


May 31, 2007 at 4:01 PM // reply »
50 Comments

Ben - great post! I'm building an quick application using Ray Camden's Soundings survey application and decided to try to convert his application to use application.cfc - and so far so good but I have run into one issue I'm not sure how best to handle - nested application.cfms...

He has an /admin section where he has another application.cfm which include the one in the root. I've done this myself in the past but not sure the best way to handle it in moving over to application.cfc...

Any thoughts?

Thanks again for all the great blog posts! I don't know how you find the time!


May 31, 2007 at 4:53 PM // reply »
7,572 Comments

@Jim,

Glad you like the work and effort that I am putting into this stuff. I know that you can extend one Application.cfc with another, however, if they are in nested directories, that will require a mapped path. I have never done this so I cannot give you any real advice other then Google "extending Application.cfc".


May 31, 2007 at 4:57 PM // reply »
235 Comments

Adobe has a full tech note on this. Search at GOogle. Sean Corfield also blogged on it.


May 31, 2007 at 7:17 PM // reply »
50 Comments

I bugged Ray about it and he pointed me to Sean's blog where indeed he has the answer!

http://corfield.org/blog/index.cfm/do/blog.entry/entry/Extending_Your_Root_Applicationcfc


Jul 19, 2007 at 11:01 AM // reply »
33 Comments

Just wanted to mention I copied your onError code as is and got an error that ARGUMENTS.Exception.RootCause.Type doesn't exist. I'm not sure you typed something wrong or my CF installation is different somehow, but RootCause doesn't exist as a key to Exception for me. There's Exception.Type, which is just a name, not something like coldfusion.runtime... Anyway, thought I'd mention this just in case.


Jul 19, 2007 at 11:04 AM // reply »
235 Comments

Yes, you need to check for the existence first. I make the mistake all the time myself.


Jul 19, 2007 at 11:17 AM // reply »
15 Comments

Yes Thomas you're right.

I noticed it only exists if your Application.cfc contains the onRequest method.


Jul 19, 2007 at 11:25 AM // reply »
7,572 Comments

Interesting. Very interesting. I have to say that I pretty much always use OnRequest() so I have never noticed this. Very good to know. Thanks.


Jul 23, 2007 at 9:28 AM // reply »
7,572 Comments

@Thomas,

Thanks for the tip. I did a quick little example to see what was different:

http://www.bennadel.com/index.cfm?dax=blog:853.view


Aug 15, 2007 at 1:36 PM // reply »
3 Comments

Hi,
I am going through converting an application.cfm to an application.cfc and am running into variables that are set in the variables scope in the application.cfm (used to be accessible in all pages of the application).

Now those variables are not accessible when I set them in the onRequestStart() or outside all the methods of Application.cfc.

The only thing I could think of to make the variables accessible from all application pages is to put them in the application or the request scope.

The problem is that I will have to add a <cfparam ..> at the top of each page that uses the variable to initialize the local variable with application/request scope variable. Can you think of anything simpler than that to accomplish the same thing?


Aug 15, 2007 at 1:40 PM // reply »
235 Comments

If yo use onRequest, then any variables you set will be in the Variables scope. This also has the side of effect of breaking Flash Remoting and Web Services, and copying other info from the CFC. Personally - I'd just use Request variables. It will help them stand out from variables made on the page itself.


Aug 15, 2007 at 1:49 PM // reply »
3 Comments

Thanks Raymond.


Aug 15, 2007 at 2:23 PM // reply »
7,572 Comments

Are you using the OnRequest() event method? That is the only way that the VARIABLES scope of the Application.cfc would be available in the processing template.


Aug 15, 2007 at 3:41 PM // reply »
3 Comments

I was not using the onRequest(). I was only using onRequestStart().
I think I may end up using the onRequest() though since there are many files to update if I use the Application/Request scope vars. The two scenarios that would be affected by using the onRequest() - Flash Remoting and WS do not apply to my app. Thanks for the info.


Aug 15, 2007 at 4:05 PM // reply »
7,572 Comments

@Ahmed,

No problem. And also, FYI, you can always conditionally delete the OnRequest() method if it is a CFC-based method call for flash remoting. But if that doesn't affect you, don't worry about it.


Aug 16, 2007 at 9:24 AM // reply »
10 Comments

Interesting Ben, how an that be done? (deleting onRequest method when making a Flash remoting or web services call)


Aug 16, 2007 at 10:11 AM // reply »
7,572 Comments

@William,

In the OnRequestStart() method, you can check the requested template. If it is a given file type (ex. .CFC) or in a certain directory or something, you can simply delete the function from the CFC scope:

StructDelete( THIS, "OnRequest" )

Then, when the ColdFusion application server finishes executing the OnRequestStart() method, it will look for OnRequest(), but it will no longer exist for that page request.


Aug 16, 2007 at 12:41 PM // reply »
10 Comments

Cool! Rule of the thumb, CFCs are objects whose properties, variables and methods can be dynamically created or removed (as in this case) at runtime.


Aug 16, 2007 at 12:45 PM // reply »
7,572 Comments

Yeah, pretty much. CFCs are super flexible that way.


Oct 9, 2007 at 4:52 AM // reply »
2 Comments

I have now tryed to use the Application.cfc. But in my code I uses cfc's in a sub catalog to make query requests.
But the problem is now that the cfc's cant see the application.DNS!?
Why is that?


Oct 9, 2007 at 7:11 AM // reply »
235 Comments

I think it depends on what you mean. You say you use CFCs in a sub catalog - do you mean subdirectory? As you know, if CF can't find an App.cfc/cfm in the current folder, it will look up higher in the directory until it finds one - so it should have no problem finding your App.cfc and if yo have app.dsn defined there, all should be well.

But - you really shouldn't be using "outside" variables in your CFCs. Why not let your App.cfc create an instances of the CFC in onApplicationStart? When you make the instance, pass in the DSN value so the CFC can store it inside itself.


Oct 9, 2007 at 7:32 AM // reply »
2 Comments

Yes I ment subdirectory.
Today I tryed to use Application.cfc again and now it worked!?
I don't know what caused the problem last time.

But your sugestion about using Application.cfc to create an instance of the cfc's that I uses sounds like a very good idea.
But how would you do that? And how should they be called from the code?
Today I call the cfc's by <cfinvoke ../>


Oct 9, 2007 at 7:45 AM // reply »
235 Comments

Typically you add a method named init to your cfcs. This method takes any configuaration parameter, like DSN. Then in App.cfc you can do
(note app = application)

cfset app.mycfc = createObject("component","path.to.your.cfc.name").init(app.dsn)>


Jan 21, 2008 at 10:33 AM // reply »
4 Comments

Hey Ben, Good stuff but are you sure you receive the application scope as a variable?

Also I have another question, I define a lot of high level stuff in those methods, yet they're completely accessible to the included template. If I don't want designers muddling with that logic, how can I make them private or inaccessible in the template's scope?

access="private" doesn't work in function definition, because the included template has private access.


Jan 23, 2008 at 10:13 AM // reply »
7,572 Comments

@Matt,

If you don't want the include to have access to the Application.cfc data, don't use the OnRequest() event method. If you exclude that method, then the requested page will simply run; but, since it is not creating a CFC mixin, then you won't have to worry about access.

If you have to use the OnRequest() event method (which I think is a wonderful method), then there is not much you can do.

What are you worried about? Developers messing with cached variables or something? I can assure you that whatever you are doing, even without the CFInclude of the requested template, developers could mess with cached data. The OnRequest() event method does not really change that at all.

I guess the variables stored in the Applicaiton.cfc via the THIS or VARIABLES scope, that is something that is OnRequest() enabled...


Jan 29, 2008 at 6:38 AM // reply »
18 Comments

Hi Ben

great tutorials and files (as ever). Thank you for everything you blog and share.

I'm a CF developer of over two years, but (ashamed to say) never used application.cfc before.
I am also on a CF8 server, and want to create a mapping to a directory to use for custom tags. I have heard that this can be done per application, but I cannot seem to get it working. I currently have the site I am working on in a /V2/ folder, with the application.cfc within.
How can I create a mapping from the .cfc to a directory to create a custom tag path?

Many thanks,

Matt


Feb 26, 2009 at 2:54 PM // reply »
19 Comments

Ben, maybe it would be a good idea to put a comment in the onRequest method that it can not be used together with cfc calls?

And/or maybe something like this in onRequestStart (commented out) for those who really want to have the onRequest in there:

<cfif listLast(arguments.targetPage,'.') is 'cfc'>
<cfset StructDelete( THIS, "OnRequest" )>
</cfif>

It is not so obvious that it does not work with cfc, because the cfc IS included and executed, and the url parames, including the method, IS available for the cfc. Still, for reasons I do not know, the cfc will not know what method to run.

Many thanks to you and this blog for helping me solve this thing. I know (now) it is described in the docs, but you really need to read it like a lawyer to see it.


RJ
May 31, 2009 at 11:23 PM // reply »
1 Comments

Thanks for all of the good examples, I am in the process of converting over an existing application.cfm to an application.cfc and used your references and examples from Skin Spider and this posting. I ran into troubles when I was trying to have an authenticated area of the website that checks for the existence of a key in the Session OnRequest and forward to a login page at a different level. It cannot find the pathing. This same code worked fine in application.cfm and its giving me some troubles here. Let me explain:

[webroot]\application.cfc = Defines application name, session management, etc.
[webroot]\applicationproxy.cfc = Stub <cfcomponent> that extends application.cfc.
[webroot]\login\index.cfm = has login and authentication code (no application.cfc)
[webroot]\members\application.cfc = authenticated area where Session.User object must exist or the user is forwarded to the ..\login\ page.

This code is returning "Could not find the included template ../login/". Any Help?

<cfcomponent
displayname="Application"
output="false"
hint="Handle the application."
extends="ApplicationProxy">

<cffunction name="OnRequest" access="public" returntype="void" output="true"
hint="Fires after pre page processing is complete.">

<!--- Define arguments. --->
<cfargument name="TargetPage" type="string" required="yes" />

<!--- If the member is not logged in --->
<CFIF StructKeyExists(Session, 'User')>
<CFIF StructKeyExists(Session.User, 'userID')>
<!--- All Good, carry on --->
<CFELSE>
<!--- The user has not logged in. --->
<cfinclude template="../login/" />
<!--- Do not allow the rest of the page to execute. --->
<cfabort />
</CFIF>
<CFELSE>
<!--- The user has not logged in. --->
<cfinclude template="../login/" />
<!--- Do not allow the rest of the page to execute. --->
<cfabort />
</CFIF>
</cffunction>

</cfcomponent>


May 31, 2009 at 11:30 PM // reply »
235 Comments

You can't cfinclude a folder. You can only include a file.


Oct 26, 2009 at 7:38 PM // reply »
45 Comments

I am being asked to clear my mysql transations from a shared hosting account. Would their be a place in the application.cfc that would be good for <cfset cfusion_dbconnections_flush()> and would this do what i need ? been looking for an ansewer i cant find it.


Oct 31, 2009 at 2:43 PM // reply »
7,572 Comments

@James,

I am not sure what you are referring to. I don't really do much of anything with databases outside of the CFQuery tag; as such, I am not sure I have any advice on some sort of transaction queue?


Dec 17, 2009 at 9:24 AM // reply »
4 Comments

I'm trying to convert my companies application.cfm to an Application.cfc but when I make the switch nothing happens. I can't get to any page, everything is just blank. It's like non of the events are being fired. I can cause an error in the Application.cfc and get some error output, but I can't even cfdump a variable. Do you have any idea what is causing this?


Dec 17, 2009 at 9:27 AM // reply »
7,572 Comments

@Steve,

It should like you are either returning "false" from the OnRequestStart() or OnApplicationStart() event or you have output="false" on your OnRequest() event.


Dec 17, 2009 at 9:44 AM // reply »
4 Comments

I checked, they both return true and onRequest has outpout="true".

I pretty much just copied you're above example. If I remember correctly i first tried running the site with the empty application example from above to see what would happen, I got a blank page.

So I started filling in the Application.cfc to see what would happen. Everything is still blank.

Is there some setting in the admin I have to change? I know it's getting processed since I can cause it to error out...idk.

Oh and I have another question. If I have some udfs that I want to be available to every page, where is the best place to include them? The onRequest? Or is it possible/good idea to make then members of the Application.cfc?


Dec 17, 2009 at 9:47 AM // reply »
4 Comments

Oh and we're running CFMX7


Dec 17, 2009 at 10:02 AM // reply »
7,572 Comments

@Steve,

Funky. If you tried running it with an empty Application.cfc and still got no output then there might be an error that's not displaying.

Have you checked the Application log file in the ColdFusion administrator to make sure there are no exceptions happening?


Dec 17, 2009 at 11:51 AM // reply »
4 Comments

You're right looks like there are some SQL errors that are not being reported.


Dec 17, 2009 at 11:53 AM // reply »
7,572 Comments

@Steve,

Ok cool. Let us know if you're still getting problems after that's fixed.


Dec 23, 2009 at 11:39 PM // reply »
2 Comments

Ben,

I like the information you posted, but I am not able to use Application.cfc with Adobe flex application.
Can you tell me how can we use Application.cfc file from Adobe Flex code ? Any help will be appreciated.


Dec 23, 2009 at 11:45 PM // reply »
235 Comments

It depends on what you mean Bran. Application.cfc is for CF. It isn't for Flex. However, if your Flex app makes a HTTP request to a CF resource within a folder that has an App.cfc, then it comes into play. Perhaps you can expand a bit on exactly what you mean?


Dec 24, 2009 at 12:50 AM // reply »
2 Comments

@Raymond,

Thanks for your response.
I want to access session variables defined in CF and check it validity from Flex application. My session variables are getting destroyed in CFC while calling from Flex. I need to test User validity(defined in session) for each request.

Do you have any idea how to achieve that using App.CFC ? Any help will be appreciated.


Dec 24, 2009 at 11:31 AM // reply »
235 Comments

Flex has multiple ways to request data from the server. The preferred way is Flash Remoting. You can use that to ask the server for session data.

Now as for ensuring it works on every request - what I say next should be taken with a grain of salt. First off - if you make use of a CFLOGON based security system, I believe you can set your FR (Flash Remoting calls) to make use of this and ensure all calls are secured. I'm not a big fan of CFLOGON myself. In the past what I've done is to pass username/password info to my service calls. This is probably not optimal though.


Dec 28, 2009 at 10:40 PM // reply »
7,572 Comments

@Raymond, @Bran,

This is a very interesting discussion. Maintaining session management across API calls is definitely something that I have thought about looking into, but have not made time to yet. When I have better ideas, I'll report back.


Jan 16, 2010 at 6:33 AM // reply »
4 Comments

Dear Ben,
don't take me as stupid, but once again I'm trying to change the Application.cfm into an application.cfc component following your tutorial, but this is what I get:

<pre><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=utf-8" http-equiv=Content-Type></HEAD>
<BODY></BODY></HTML>
</pre>

I have followed all your indications for each event displacing every part of the initialization code in the right function, but nothing happens.
Why is that ?

Thanks in advance for any help you may provide

Sergio


Jan 16, 2010 at 6:34 AM // reply »
4 Comments

Sorry for the "<pre>" tag. It is mine, not in the original code.


Jan 16, 2010 at 8:25 AM // reply »
4 Comments

SORRY.
Forget about what I wrote before.
After reading this thread I went into a debug session and I discovered the problem: an error in the code also unsupported by the fact that the OnError event was empty.
Thanx however!

Sergio


Jan 16, 2010 at 1:56 PM // reply »
4 Comments

BEN!
Thanks a lot for this tutorial.
It is great, as all the contents in this website.
Stay so well.
Sergio


Jan 16, 2010 at 3:56 PM // reply »
7,572 Comments

@Sergio,

No worries - glad you got it working.


Jan 20, 2010 at 10:26 AM // reply »
5 Comments

Hi Ben,

I have a problem regarding the application.cfc and setting session.user struct. It seams to work just fine when user first logs in or after the manual logout, but if session expires and user tries to log back in I am getting session.user.xyz is not found. I am using j2ee for session management. Thanks for your help in advance and here is my application.cfc

<cfcomponent>
<cfparam name="loginQuery.news" default="0">
<cfparam name="loginQuery.calendar" default="0">
<cfparam name="loginQuery.account" default="0">
<cfparam name="loginQuery.site" default="0">
<cfparam name="loginQuery.marketing" default="0">
<cfparam name="loginQuery.users" default="0">
<cfinclude template="/Application.cfc">
<cfset This.name = "Login">
<cfset This.Sessionmanagement="True">
<cfset This.clientManagement = "true">
<cfset This.loginstorage = "session">
<cfset THIS.SessionTimeout = CreateTimeSpan( 0, 0, 0, 1) />

<cffunction name="OnRequestStart" >
<cfargument name = "request" required="true"/>
<cfif IsDefined("URL.logout")>
<cflogout>
<cflocation url="/index.cfm" addtoken="no">
</cfif>
<cflogin>
<cfif NOT IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<cfif cflogin.name IS "" OR cflogin.password IS "">
<cfoutput>
<h2>You must enter text in both the User Name and Password fields.</h2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<cfquery name="loginQuery" dataSource="#Application.DNS#">
SELECT UserID, UserLevel, news, calendar, site, marketing, account, users
FROM Users
WHERE
UserID = '#cflogin.name#'
AND Password = '#cflogin.password#'
</cfquery>
<cfif loginQuery.UserLevel NEQ "">


<cfloginuser name="#cflogin.name#" Password = "#cflogin.password#" roles="#loginQuery.UserLevel#">
<cfset SESSION.User = StructNew() />
<cfset SESSION.User.news = loginQuery.news/>
<cfset SESSION.User.calendar = loginQuery.calendar/>
<cfset SESSION.User.account = loginQuery.account/>
<cfset SESSION.User.marketing = loginQuery.marketing/>
<cfset SESSION.User.site = loginQuery.site/>
<cfset SESSION.User.users = loginQuery.users/>


<cfelse>
<cfoutput>
<H2>Your login information is not valid.<br>
Please Try again</H2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
</cfif>
</cfif>
</cfif>
</cflogin>
</cffunction>
<cffunction name="onSessionEnd">
<cfset StructClear(Session)>
<cflocation url="/index.cfm" addtoken="no">
</cffunction>
</cfcomponent>


Jan 20, 2010 at 11:09 PM // reply »
7,572 Comments

@Almir,

Unfortunately, I don't know much about ColdFusion's built-in functionality. Is the problem occurring constantly once it pops up? Or does it happen once and then go away?

I am not sure I understand the CFInclude of "Application.cfc"? Aren't you in Application.cfc? Is this file including itself :)

Also, You don't have to clear the SESSION in OnSessionEnd(). Actually, in OnSessionEnd(), I don't even think that the session object is accessible... there is not way to run CFLocation (or no reason to) in OnSessionEnd() since it is not a traditional page request (made by the user).


Jan 21, 2010 at 10:12 AM // reply »
5 Comments

Hi Ben, thanks for responding.

The problem seams to stick one it pops up. So if I log in and get an error then it will stick until I log out and lag back in. I am not understanding what is the difference between <cflogout> and session expiring on it's own and loging back in after these 2 events.

I am including application.cfc from the root that has all the application settings and then this application.cfc is in my secure folder. I do not need user management for the whole site.

Originally I had nothing in OnSessionEnd but I've been trying to figure out this problem.

Another thing I tried is placed creation of session.user. struct in the OnSessionStart and it seams to be working every time but the only problem it's not seeing the "loginQuery" and it's using default settings from the <cfparam>.
I am not sure how can I pass user info to the OnSessionStart function.

Thanks


Jan 21, 2010 at 12:59 PM // reply »
5 Comments

Quick Update, I removed onapplicationstart from the root application.cfc and placed it into this one just to eliminate any possibilities. I am still getting same problem.


Jan 21, 2010 at 8:47 PM // reply »
7,572 Comments

@Almir,

As far as the OnSessionEnd(), ColdFusion passes it two arguments - the currently ending session scope and the existing application scope. That is how you can get the user info (from the session scope passed-in).

As far as session vs. CFLogin system, that's a bit tricky, and part of why I am not crazy about the CFLogin system. From what I remember the few times that I have looked into it, the CFLogin "login" lasts *longer* than the session timeout.

Actually, now that I think about it, that makes perfect sense. Since you are using CFLogin checks to set your SESSION-based data, it's possible that your session would time out, but not be re-populated because ColdFusion still things you are logged in via CFLogin.

I'll try and due a bit of experimentation with this idea.


Jan 22, 2010 at 9:54 AM // reply »
5 Comments

Ok that makes sense now. I did notice that at times if expired session sits for a while I was able to login with user struct set. Would it be possible to do <cflogout> on OnSessionEnd() or maybe set timeout for the <cflogin>?


Jan 22, 2010 at 3:05 PM // reply »
5 Comments

Setting idle timeout on cflogin will fix this: <cflogin idleTimeout="n"> CF default value for cflogin idle timeout is 1800 which is 30 min. Thank you for your help and setting me on the right track.


Jan 22, 2010 at 4:38 PM // reply »
7,572 Comments

@Almir,

No problem. I'm glad I happen to remember something about the timeout issues :) I think using the CFLogout in the OnSessionEnd() might be good. Changing the timeout might also be good. I don't have enough experience with that login system to say which is better.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 20, 2010 at 12:07 PM
Drawing On The iPhone Canvas With jQuery And ColdFusion
Simply awesome. Saved my day. ... read »
Mar 20, 2010 at 9:00 AM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
I would like to say thx for an easy way to create a bottom bar. I do have a ?. Is it possible to center the bar if i want to resize it to ex 85%. Regards Offenbach ... read »
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »
Jim
Mar 19, 2010 at 4:44 PM
Shoot 'Em Up Starring Clive Owen And Paul Giamatti
I actually enjoyed this movie quite a lot. It was different, certainly, but I think they were going for more of a Quentin Tarentino-"wow, that was weird"-vibe than an actual spoof. Once I realize ... read »
Mar 19, 2010 at 4:34 PM
An Intensive Exploration Of jQuery With Ben Nadel (Video Presentation)
Hey I guess the video is down. Is there anyway you can upload to youtube or vimeo or some other service? Greatly appreciated. ... read »
Mar 19, 2010 at 4:24 PM
ColdFusion CFPOP - My First Look
@Ben Thanks for the follow up! The root of the problem had to do with being able to trace bounced emails to specific records in a DB table. Let's say you run an email campaign and you get 1,000 bou ... read »