Application.cfc, one that will work for you.

Went through some trials and tribulations with Application.cfc this afternoon. I used what livedocs gave me, and tested the various functionality associated with each supported native function i.e. onRequestStart, onSessionStart, etc. I found some quarks with their documentation and developed an Application.cfc that works with the way I think their coder/documentation individual meant it to.

So here it is, the biggest problem I saw was with onApplicationEnd. This always throws an error so cflogging was impossible in the method but had to be trapped in onError. Hope this clears up some things for you. Now go convert over your Application.cfm, this is powerful stuff.

Update 1/12/2006: This blog entry featured at coldfusionpodcast, have a listen.

<cfcomponent>
<cfscript>
       this.name = "theApp";
       this.applicationTimeout = createTimeSpan(0,0,0,1);
       this.clientmanagement= "yes";
       this.loginstorage = "session" ;
       this.sessionmanagement = "yes";
       this.sessiontimeout = createTimeSpan(0,0,0,1);
       this.setClientCookies = "yes";
       this.setDomainCookies = "no";
       this.scriptProtect = "all";   
   </cfscript>
   
   <cffunction name="onApplicationStart" output="false">
       <cfscript>
         //set your app vars for the application          application.dsn = "theDSN";
         application.sessions = 0;
       </cfscript>
      
       <cftry>
            <!--- Test whether the DB is accessible by selecting some data. --->
            <cfquery name="testDb" datasource="#application.dsn#" maxrows="2">
                SELECT COUNT(userId)
                FROM users
            </cfquery>
            <!--- If we get a database error, report an error to the user, log the
                     error information, and do not start the application. --->

            <cfcatch type="database">
                <cflog file="#this.name#" type="error"
                     text="DB not available. message: #cfcatch.message# Detail: #cfcatch.detail# Native Error: #cfcatch.NativeErrorCode#" >

            
                <cfthrow message="This application encountered an error connecting to the database. Please contact support." />      
            
                <cfreturn false>
            </cfcatch>
       </cftry>
      
       <cflog file="#this.name#" type="Information" text="Application #this.name# Started">
      
       <cfreturn True>
   </cffunction>
   
   <cffunction name="onApplicationEnd" output="false">
      <cfargument name="applicationScope" required="true">
   </cffunction>
   
   
   <cffunction name="onSessionStart" output="false">
      <cfscript>
         session.started = now();
      </cfscript>
      
      <cflock scope="application" timeout="5" type="Exclusive">
         <cfset application.sessions = application.sessions + 1>
      </cflock>
   </cffunction>
   
   <cffunction name="onSessionEnd" output="false">
       <cfargument name = "sessionScope" required=true/>
       <cfargument name = "applicationScope" required=true/>
       <cfset var sessionLength = TimeFormat(Now() - sessionScope.started, "H:mm:ss")>
      
       <cflock name="AppLock" timeout="5" type="Exclusive">
            <cfset arguments.applicationScope.sessions = arguments.applicationScope.sessions - 1>
       </cflock>
      
       <cflog file="#this.name#" type="Information"
            text="Session #arguments.sessionScope.sessionid# ended. Length: #sessionLength# Active sessions: #arguments.applicationScope.sessions#">

   </cffunction>
   
   <cffunction name="onRequestStart">
       <cfargument name="requestname" required=true/>
       <!--- Regular maintenance is done late at night. During those hours, tell
                  people to come back later, and do not process the request further. --->

       <cfscript>
            if ((Hour(now()) gt 1) and (Hour(now()) lt 3)) {
                WriteOutput("The system is undergoing periodic maintenance.
                     Please return after 3:00 AM Eastern time."
);
                return false;
            } else {
                this.start=now();
                return true;
            }
       </cfscript>
      
       <!--- Check for login here --->
   </cffunction>
   
   
   <cffunction name="onError" output="true">
       <cfargument name="exception" required=true/>
       <cfargument name="eventName" type="String" required=true/>
       <!--- Log all errors. --->
      
      
       <!--- Display an error message if there is a page context. --->
       <cfif (trim(arguments.eventName) IS NOT "onSessionEnd") AND (trim(arguments.eventName) IS NOT "onApplicationEnd")>
            <cflog file="#this.name#" type="error"
                text="Event name: #arguments.eventName#" >

            <cflog file="#this.name#" type="error"
                text="Message: #arguments.exception.message#">

               
            <cfoutput>
                <h2>An unexpected error occurred.</h2>
                <p>Please provide the following information to technical support:</p>
                <p>Error Event: #arguments.eventName#</p>
                <p>Error details:</p>
            </cfoutput>   
            <cfdump var=#arguments.exception#>
         <cfelseif (arguments.eventName IS "onApplicationEnd")>
               <cflog file="#this.name#" type="Information"
            text="Application #this.name# Ended" >

</cfif>
</cffunction>

</cfcomponent>

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Excellent article and code. Worked very well. Now I have to make session expire on user logout.
# Posted By G | 12/2/05 9:49 PM
Thanks for the sample code, I've been wrestling with LiveDocs myself. You've given me a head start!
# Posted By rak | 1/12/06 7:16 PM
Nice post! Helped explain alot.

One question. if you didnt have access to cflog (ie. in a shared hosting environment) what do you recommend logging to? Email? TextFile?
# Posted By Bill | 2/2/06 4:44 AM
Bill,

If you don't have access to cflog, I would think you would most likely not have access to cffile. Unless of course your plight is due to a version issue, sorry if it is. This is strictly an implementation issue and I would err on the side of writing to a text file if the capability exists. Use email only for &quot;Critical&quot; issues, i.e. an email associated with a pager or something of that nature. The reason being that if you do end up going through some type of error scenario on your machine you don't want your inbox filling up with the same error and you sure as heck do not want to be paged for every error as well 8-). Hope that helps, good luck.
# Posted By Jeff Bouley | 2/9/06 2:36 PM
Jeff, excellent website buddy! I hope you and Shannon are doing well. I am good. I will see if you can figure out who this is :-)
# Posted By John Cooper | 8/7/06 11:25 PM
Wonderful article!

Even though I have been developing exclusively in CF for 6 years or so, I have been oblivious to Application.cfc! Oh the joys of working for a small company who doesn't believe in R&D.

Anyway, your code is really clear to follow and has certainly made me go 'wow'! I can really see the potential in this. I've been using the same application.cfm for a number of years now. Time for a big change over me thinks.
# Posted By James Allen | 9/12/07 7:09 PM
Hi James, you made my day!
# Posted By Jeff Bouley | 9/12/07 8:55 PM
What is the prupose of setting the sessionTimeout and the applicationTimeout to 1 sec?
# Posted By james | 11/5/07 4:06 PM
James, I did that only to test the onAppEnd and onAppStart code. This is just an example. Didn't mean to confuse. Thanks.
# Posted By Jeff Bouley | 11/5/07 4:38 PM
Hi, I am currently using application.cfm in which i have set datasource, sessions, sitelocation, and some other variables. Now I want to convert application.cfm in to application.cfc. I am trying to write a piece of code as follows

<cffunction name="onRequestStart" output="true">
<cfset client.memberlanguage = "english">
<cfset client.sitelanguage = "english">
<cfset headerfile = "headerfile.cfm">

and more variables...

</cffunction>

When I run my code i am getting varible not defined error message on my page. Can someone assist, what am i doing wrong here?

Thanks
# Posted By Parag Shah | 11/6/07 4:41 AM
Parag, you do not want set client vars in onRequestStart. Those are related to session and should be in onSessionStart to setup with default language settings. Then based off what they select via form or some other site feature.

onRequestStart runs for every request, so only set variables that are absolutely necessary to set for each page request. To answer your question I do not readily see any immediate problem with the variable sets in your code example. My guess is that it is happening somewhere else in your onRequestStart.

Make sure you turn on the advance debug output via the ColdFusion administrator. It will give you line number in your Application.cfc where the error is actually occurring. Good luck.
# Posted By Jeff Bouley | 11/6/07 8:20 AM
Thanks Jeff for response

I have now included the variables in onSessionStart function and I am still getting an error on my index.cfm page where i have included headerfile as <CFINCLUDE TEMPLATE ="#headerfile#"> I am getting error as
Variable HEADERFILE is undefined.
What could be the problem here?

Also can we have cfparam declared within onSessionStart function?

Thanks
# Posted By Parag Shah | 11/6/07 9:02 AM
Jeff,

One more thing, i have my application.cfm file sitting in the site root. . Should that be a problem here? Do i need to remove the application.cfm file from the code?

Thanks
# Posted By Parag Shah | 11/6/07 9:05 AM
Parag, wow, I'm very concerned about your last 2 entries and I highly suggest you read up on memory variables in CF. Application, Session, Server.

For a global setting (like headerfile var) it is best to place in Application scope (put in onApplicationStart) and don't change it anywhere but there to avoid possible memory issues. (you should look into cflock and why it can help with memory vars).

Your cfparam question is not needed and I avoid it at as it is a bit of a blanket approach to development. Better to use isDefined in my opinion.

If you are going to use Application.cfc remove the existing Application.cfm. Feel free to take this off-line and email me with your specific questions or code files. It sounds like you are just setting up the application and I want to make sure you get off on the right foot.
# Posted By Jeff Bouley | 11/6/07 8:58 PM
Hi Jeff,

I have tried the following piece of code from my application.cfm to convert it into application.cfc ...


<cfcomponent>
<cfset this.name = "myapp">
<cfset this.clientmanagement = "True">
<cfset this.loginstorage = "Session">
<cfset this.sessionmanagement = "True">
<cfset this.sessiontimeout = "#createtimespan(0,0,20,0)#">
<cfset this.applicationtimeout = "#createtimespan(0,1,0,0)#">

   
   <cffunction name="onApplicationStart" output="no">
<!--- onApplicationStart body goes here --->

   <CFSET application.datasource = "myappdatasource">
      <CFSET application.ds = "myappdatasource">
      
      <cfset application.headerfile = "header.cfm">
      <cfset application.footerfile = "footer.cfm">
      <cfset application.adminheaderfile = "sysheader.cfm">
      <cfset application.adminfooterfile = "sysfooter.cfm">
      <cfset application.sectionid = "5">
      
      <cfset application.submissionemail='test@test.com'>
      
      <cfset client.memberlanguage = "english">
      <cfset client.sitelanguage = "english">
      <cfset client.language_suffix = "">
      <cfset client.showeditbar = "0">
      
      <cfset client.pagename = "home">
      <cfset client.sectionname = "Main">
      <cfset client.showroot = "no">
      
      <CFSET client.sitelocation = "http://mywebsite.com/">

      <CFSET client.secsitelocation = "https://mywebsite.com/">
         
      <CFSET client.webservicelocation = "http://mywebsite.com/webservice.asmx?WSDL">
      
      <CFSET client.virtualpath = "">
      
      <cfset client.editorpath="">
      <cfset client.editorRpath="/uploads/">
      <cfset client.editorBasepath=ExpandPath("./../../..")>
         
      <CFSET client.hostemail = "test@test.com">
      <CFSET client.registrationemail="test@test.com">
      <cfset client.orderemail="test@test.com">
      <cfset client.contactemail="test@test.com">
      <cfset client.approvalemail="test@test.com">
      <cfset client.contactemail1="test@test.com">
      <cfset client.formtoolfromemail="test@test.com">         
      <CFSETTING SHOWDEBUGOUTPUT="No">
      <cfset client.discussionemail="test@test.com">
   

      <cfset client.imagePath="../images/english/formcreator/">
      
      <cfset client.showFormToolDataSet=0>      
      
      <cflock scope="APPLICATION" type="EXCLUSIVE" timeout="10">
         <cfobject component="cfcs.Categories" name="application.cfcs.Categories">
      </cflock>
      
      <cfset client.picofweekpath = "#virtualpath#picofweek/images">
      <cfset client.staffThumbpath = "#virtualpath#staffphotos/thumbnails">
      <cfset client.staffActualpath = "#virtualpath#staffphotos/images">

      <cfset client.PicGalleryThumbpath = "#virtualpath#picturegallery/thumbnails">
      <cfset client.PicGalleryActualpath = "#virtualpath#picturegallery/images">
      
      <CFIF #ParameterExists(url.changelanguage)#>
         <CFSET client.memberlanguage = "#changelanguage#">
      </CFIF>
      
      <cfif client.memberlanguage is "French">
         <cfset client.langsuff="french">
         <cfset client.imagedir="french">
      <cfelse>
         <cfset client.langsuff="">
         <cfset client.imagedir="english">
      </cfif>
      
      <CFSET client.querystring = "">
      <CFLOOP LIST="#CGI.QUERY_STRING#" INDEX="index" DELIMITERS="&">
         <CFIF NOT #FindNoCase("changelanguage",index)#>
            <CFSET client.querystring = #client.querystring# & "&#index#">
         </CFIF>
      </CFLOOP>
            
      <CFSET client.template = #ListLast(CGI.CF_TEMPLATE_PATH,"\,/")#>
      
      <CFSET client.uploadimagepath = #ExpandPath("./uploads")#>
      <CFSET client.uploaddocumentpath = #ExpandPath("./uploads")#>
      <CFSET client.uploadwebpath = "#sitelocation#uploads">
      
      <CFSET client.sitename = "My Site">
      <CFSET client.querycachedtime = #CreateTimeSpan(0,0,0,0)#>
      <CFSET client.SiteSuperAdmin = 1>
      <CFSET client.SiteAdmin = 2>
      <CFSET client.SiteSubAdmin = 5>
      <CFSET client.HostName = "My Site">
      <CFSET client.sitedbtype = "sql">
      
      <CFSET client.thumbnailpath = ExpandPath(".\picturegallery\thumbnails")>
      <CFSET client.actualimagepath = ExpandPath(".\picturegallery\images")>
      
      <CFSET client.staffthumbnailpath = ExpandPath(".\staffphotos\thumbnails")>
      <CFSET client.staffactualimagepath = ExpandPath(".\staffphotos\images")>
      
      <CFSET client.picofweekimagepath = ExpandPath(".\picofweek\images")>
            
      <CFSET client.isMSIE = #FindNoCase("MSIE",CGI.HTTP_USER_AGENT)# OR #FindNoCase("Firefox",CGI.HTTP_USER_AGENT)#>
      
      <cfset client.FrenchMonthsName = 'Jan, Fév, Mars, Avr, Mai, Juin, Juil, Août, Sept, Oct, Nov, Déc'>
      
      <cfreturn />
</cffunction>

<cffunction name="onApplicationEnd" output="no">
<cfargument name = "ApplicationScope" required="true" />
<!--- onApplicationEnd body goes here --->   
      

</cffunction>


<cffunction name="onSessionStart" output="true">
<!--- onSessionStart body goes here --->

<!--- This is where you would put code to initialize any session variables --->      
      <cfparam name="session.sitelanguage" default="English">
      <cfparam name="session.membertypeid" default="18">
      
      <cfparam name="session.brdpath" default="DefaultBoardRoomPath">
      <cfparam name="session.argLocation" default="DefaultArgLocationPath">
      <cfparam name="session.wholepath" default="DefaultWholePath">
      
      <!--- Comments added by VL07 on 03-27-2007 --->
      <cfinclude template="FreeURL.cfm">
      <!--- Comments ends by VL07 on 03-27-2007 --->            
      
      <CFIF #ParameterExists(session.loginid)#>
       <CFSET session.thiscurrentpage = #ListLast(CGI.CF_TEmPLATE_PATH,"\,/")#>
         <CFIF Len(Trim(CGI.query_string))>
          <CFSET session.thiscurrentpage = #session.thiscurrentpage# & "?#CGI.QUERY_STRING#">
       </CFIF>
      </CFIF>

      <cf_sessioncheck>
      
</cffunction>

<cffunction name="onSessionEnd" output="true">
<cfargument name = "SessionScope" required=true/>
<cfargument name = "ApplicationScope" required=true/>
      
<!--- onSessionEnd body goes here --->
      
</cffunction>

<cffunction name="onRequestStart" output="true">
<!--- OnRequestStart body goes here --->
      
      <cfswitch expression="#session.sitelanguage#">
         <cfcase value="French">
            <cfset request.sys_imagepath = "#virtualpath#images/English/system">
            <cfset request.site_imagepath = "#virtualpath#images/French/Site">
         </cfcase>
         <cfdefaultcase>
            <cfset request.sys_imagepath = "#virtualpath#images/English/system">
            <cfset request.site_imagepath = "#virtualpath#images/English/Site">
         </cfdefaultcase>
      </cfswitch>
      
</cffunction>

   <!--- <cffunction name="onRequestEnd" output="true">
<!--- OnRequestEnd body goes here --->
<cfoutput>OnRequestEnd executed<br></cfoutput>
</cffunction> --->

<!--- onError is equivalent to CFERROR in application.cfm --->
<!--- <cffunction name="onError">
<cfargument name="Exception" required=true/>
<cfargument type="String" name="EventName" required=true/>
<!--- Log all errors. --->
<cflog file="#This.Name#" type="error" text="Event Name: #Arguments.Eventname#">

<cflog file="#This.Name#" type="error" text="Message: #Arguments.Exception.message#">

<cflog file="#This.Name#" type="error" text="Root Cause Message: #Arguments.Exception.rootcause.message#">

<!--- Display an error message if there is a page context. --->
   <cfif NOT (Arguments.EventName IS "onSessionEnd") OR (Arguments.EventName IS "onApplicationEnd")>
<cfoutput>
<h2>An unexpected error occurred.</h2>
<p>Please provide the following information to technical support:</p>
<p>Error Event: #Arguments.EventName#</p>
<p>Error details:<br>
<cfdump var=#Arguments.Exception#></p>
</cfoutput>
</cfif>
</cffunction> --->

</cfcomponent>
# Posted By Parag Shah | 11/7/07 5:22 AM
really nice code
# Posted By Srihari | 1/22/09 9:20 AM
@Parag Shah.
Wow. Its time to stop your developing and do some studying.
This is not the right way to build an application.
# Posted By Pepperman | 3/27/09 5:26 PM
Excellent article and code. Worked very well. Now I have to make session expire on user logout.


Anna
________________
http://skylinemp3.com/
# Posted By Anna | 12/4/09 10:00 AM

Copyright Strikefish, Inc., 2005. All rights reserved.