Application.cfc Scoped Functions Are Stored In Page VARIABLES Scope
Holy cow! I just realized that Application.cfc-scoped methods such as OnApplicationStart() and OnRequestStart() as well as any other custom user-defined ColdFusion functions (in the Application.cfc) are stored in and are accessible via the current page's VARIABLES scope. Meaning, you can call things like:
<!--- Call application event. ---> <cfset VARIABLES.OnApplicationStart() /> <!--- Call UDF. ---> <cfset VARIABLES.UDFDefinedInAppCFC() />
This seems a bit silly to me, but I am glad I'm finally aware of this.
Want to use code from this post? Check out the license.
That's great to know! I have a couple of extra functions in my App.cfc that I use for logout/login and other stuff. I was bummed I couldn't access that same code from other templates. Sweet find!
Yes that is the case with application.cfc. You can set up your own UDF's in the application.cfc and you can call them from any of your pages of course as long as the function is set to public. I've seen some people include it in the onRequestStart() (I think that was the one) but then they have to put it in the request scope just to access it. If you ask me its just much easier to drop in to application.cfc.
Keep up your exploration!
Yeah, I hear you on the AJAX and CFC issues and OnRequest(). Ray Camden came up with a good solution for that by basically deleting the OnRequest() method whenever a CFC is called directly (or some sort of flash remoting, but I don't remember that one).
What's the best way to make these UDF's defined in the app.cfc available to the code run in custom tags?
I am not sure why you want to do that, but I suppose you could store a reference to the Application.cfc in the REQUEST scope. In your OnRequestStart() method, you could have something like:
<cfset REQUEST.Application = THIS />
Then, in your custom tags you could something like:
<cfset REQUEST.Application.OnRequestEnd() />
Not sure why, but I suppose that would work.
Maybe I didn't explain it well, but regardless, I found this article to answer my question:
Thanks for the quick reply!
Ok cool. Good luck.
I have been converting my CMS arch to use app cfc from cfm the last little while and all this talk about onRequestStart/ajax interference freaked me out. I have discovered, and if you think about it, it is logical, onRequestStart has NO inherent interference with AJAX calls. The problem is with this 'template' of an application.cfc that certain circles are using where you try to cfinclude the requested cfm/cfc page/call. If you are not doing that, you need no special handling, no special logic to handle a direct remote cfc/ajax call. It works FINE. I feel MUCH better about converting to app cfc now and this also have reconfirmed my faith in the Adobe programmers whom I had a hard time believing would create an onRequestMethod that wouldn't allow cfc/ajax calls natively! I commented my results on Ray's blog after it was suggested it might be the actual onRequestStart causing the issue. Of course this brings into question the use of a template that requires special handling to re-fix something that wasn't broken. But if it works for you and you like it that way, cool cool. I'll continue to let my index.cfm handle the content driver cfc and the onRequest will just handle security cfc call and other aspect oriented programming calls with no special logic needed to handle cfc/cfm differentiation or manual invokes. There is no bug or issue, the onRequestStart works CORRECTLY and as expected. Much to my relief!
And thanks, Ben, for discovering the way to call app cfc functions outside of itself! I was having a hard time guessing where they ended up and I couldn't get the app cfc to instantiate like other cfc's which was very strange indeed! That is what I was actually looking for!
It is the OnRequest() method that causes some CFC-based call problems, not OnRequestStart() - in case there was any confusion. Having the OnRequestStart() should never cause any problems.
Ah, that makes more sense. And makes me feel better. I must have sadly missed this distinction on this and Ray's blog. This thread was tackling both (for different reasons). I just read the Adobe docs on the onRequest() and it does explicitly state it is an interrupter for the page content and the page called (index.cfm, hoho.cfm, or myAjax.cfc) needs to be explicitly handled by the programmer. So the workarounds are effectively doing what the docs tell you that you have to. So this isn't as crazy as I thought it was, but it does appear Adobe has correctly warned us about this method. My AOP/Security pre-request (it used to be in application.cfm before the target page/cfc would get called, effectively onRequestStart() ) handles all the security, redirection and special cases already so it won't change for me. I won't need to use the onRequest method and will let a request make its natural call if it gets by onRequestStart().
Thanks for setting me straight!
No problem my man. I like to use OnRequest() to force people to include index.cfm no matter what is requested; but, for the most part, unless you are changing the template that gets requested, there is no real need for the OnRequest() method (and, as you see, it can cause problems).
Also, take a look at this for a conversation on deleting the OnRequest() method programmatically based on the type of page request:
hum... i may be back to where i started in a way on my original reason i read through this thread (not onRequest related).
i am trying to call application.cfc methods directly from another cfc that is invoked by the application cfc methods.
in short, on app initialization (onApplicationStart), i am creating some low level objects that don't have access to a more general error handler (because it is not created yet and depends on the low level stuff) and if these fail, i'd like to have them call onError (which basically does a more crude dump/basic email/txt msg of the error passed in so admins will be notified post haste.
so although variables.onError seems to work for a PAGE, it does not seem to be working inside a cfc.... i can extend application into the cfc and that works, but not as elegant as i wanted esp if there end up being lots of cfc's that need onError or other cfc's in the application.cfc. (prob not, just thinking ahead).
i guess i can create a cfc that extends and then inject the methods into the application core object methods so it is included in the constructors that pull in my core methods... just seems like if you can get to variables from a cfm, there should be a way to grab it from inside a cfc... guess that keeps the variables scopes protected from each other so it makes sense, but.... still.... any ideas? i guess i can also (re)throw (chain the catches) and push the stuff up which would then hit onError.. a bit cumbersome but that would work too...
maybe extending is the simplest solution afterall.
Here is an oddity (to me) i couldn't see much/anything written about. Not really explained in cf docs, the arg is referenced, but not the behaviour. Maybe others have discovered this too.
So after eschewing onRequest(), but continuing to use onRequestStart() for all things AOP (security mainly), i was adding some more tracing/dump/logging options and added some explicit arguments which subsequently throw the method. I thought, "What? I'm not passing any arguments in yet... "
I was overloading all the arguments up until then. What i discovered is the Application provides your first argument to this method just like onRequest(), (at least when it is naturally fired off, haven't tested explicit calls yet), and it is the targetpage value (index.cfm for example). Since I had no args before, it was forcing it into my next arg regardless and failing on type (TraceOn is a boolean, for instance). So although you can ignore the hard-wired argument and don't need to set the argument explicitly (you can run it with no cfarguments), you cannot use explicit arguments unless you also include the first one as the targetPage (doesn't really matter what you call it, but the first arg will always get the page requested value).
I am not sure that I fully understand what you are saying. Are you basically saying that you add additional arguments parameters to OnRequest()? If so, yes, the first one will *always* be the target page requested by the user.
yes, i was using argumentCollection to overload onRequestStart() with no defined arguments and handling them myself, but as soon as I used a named <cfargument>'s CF would always force the target page into my first argument. I did not expect this. But it elucidates why onRequest() is a problem as well as it does the same thing this way and forces you to process this low-level hardwired argument.
Hmm, that's interesting that the behavior would change when you use named arguments vs. argumentCollection. I guess the ARGUMENTS scope is just trying to reconcile the method signature (what it's expecting) with what you send it.
Ben, sorry to keep resurecting an old post. I'm don't consider myslef a CF noob, but I'm having a hell of a time figuring out why I'm getting "The [method name] method was not found.: Either there are no methods with the specified method name and argument types, or the testMeth method is overloaded with argument types that ColdFusion cannot decipher reliably."
In Application.cfc I've go the following...
<cffunction name="testMeth" output="false" access="public" returntype="string">
<cfreturn "testMeth output!">
And on a test page, in the same directory, I'm callling...
Yet I'm getting the above mentioned error. Worse, when I CFDUMP the variables structure, it shows no object or data. Empty. Ugh.
Is there something special I'm supposed to do in Application.cfc to get the methods into the variables scope? Any help? Many thanks!
which event is creating/instantiating your object? are you recreating the cfc in onRequest so it runs on every call? this would probably work... but you are reinstantiating the cfc every request. if you put it in some of the other events it isn't as obvious; i've found referencing a function put in some of the app cfc events is problematic and i've had to explicitly instantiate a copy of the methods i wanted to use. just putting cfc code in some parts (some events) of the app cfc does not necessarily instantiate them and make them available to the whole application unless you explicitly (manually) do so.
Thank you for the fast, kind reply. What I have is a pretty generic Application.cfc file with OnApplicationStart(), OnRequestStart(), and onError() methods only. That worked fine. But then I added the <cffunction> block (in my previous post) before the end of the </cfcomponent> end tag and the test method "testMeth()" and it simply isn't being recognized. Based on Ben's initial post above that "as any other custom user-defined ColdFusion functions in the Application.cfc" I trued the VARIABLES.testMeth() but it's giving me hassles.
The problem is that unless you use the OnRequest() event to include the executed template, the given template does *not* have access to the Application.cfc instance. By using the OnRequest() event method, you are creating a mixin, which makes the executing page, essentially, part of the Application.cfc:
I finally had a minute to try this and it worked. Thank for all the help.