Remote Synthesis
Search my blog:
Viewing By Entry / Main
Nov 28, 2005

Application CFC and UDF Libraries

I am working on a project at work where I decided to finally make the leap into using application.cfc instead of application.cfm. I have found this to be a slightly tougher transition than I anticipated. One thing I came across today is that I usually included a common library of functions in my application.cfm file just using a simple cfinclude so as to make the functions available on every page. Either my brain is totally fried right now or this isn't as easy to do using application.cfc, but I have come up with three options and not sure which one I might choose.Option 1 - include in the onRequest method
This seems easy enough. Create an onRequest method in your cfc with the following code:

<cffunction name="onRequest">    <cfargument name="targetPage" type="String" required=true/>    <cfinclude template="lib.cfm" />    <cfinclude template="#arguments.targetPage#"> </cffunction>

However, there is one problem with this is that the ColdFusion documentation for the onRequest method in application.cfc states:

Do not implement the onRequest method in any Application.cfc file that affects .cfc files that implement web services, process Flash Remoting or event gateway requests; ColdFusion MX will not execute the requests if you implement this method.

This could present a problem for my app, though I could work around it potentially.

Option 2 - include in the onRequestStart method and copy into a scope
If you simply do a cfinclude in your onRequestStart method, the functions will be copied into the variables scope of the component because onRequestStart does not have access to the variables scope of the calling page (or at least that is how I understand it). To work around this, I found a found to copy UDFs into another scope. However, this uses the caller scope and the isCustomFunction function, which aren't useful in this scenario. Therefore, I modifed the code to copy the UDFs into the request scope as follows:

<cfinclude template="lib.cfm" /> <!--- copy UDFs into request scope ---> <cfloop collection="#variables#" item="key">    <cfif NOT structKeyExists(this,key) AND NOT isStruct(variables[key])>       <cfset request[key] = variables[key]>    </cfif> </cfloop>

This just copies out functions that don't exist in the this scope. It worked nicely, but I am not completely comfortable running this on every request. I could easily stick it in the application scope, but I am not sure that is where I want my UDFs since the CF documentation states:

Application scope functions can cause processing bottlenecks because the server can only execute one copy of the function at a time. All requests that require the function must wait their turn.

NOTE: I was informed this is incorrect info from 6.1 docs. It is neither true for versions 6.1 or 7. See comments below.

Option 3 - Utilize COAL
The last option is to utilize the ColdFusion Open Application Library (COAL) developed by Ryan Guill to make my UDFs (and many other useful utilities) available as "services". This has other benefits as well and I like this option, but am concerned about adding another layer of complexity that I will have to train everyone on the team to understand.

I haven't yet decided on a solution. Am I missing something obvious? Or maybe something not obvious but better?

Comments
Ryan Guill
Im not sure, but *could* you copy the function into the request scope using the onRequestStart() ?

Personally, creating an object out of your functions would be the best way to go, whether you use COAL or not. But COAL would be a good fit for this!

I hope to have a new version of COAL out soon too, so stay tuned to that if you are still considering it as an option.


Brian Rinaldi
Thanks Ryan. That is essentially what I am doing in option 2, except that I don't want to have to know what UDF's are in the file for this to work (I could even do it within the include itself I suppose as well). The solution I posted will move all UDFs (I believe - it hasn't been tested too thoroughly to be quite honest). As for COAL, I am still considering it as this project is in its very early stages. Keep me posted on the new version.


Luis Majano
Brian,

Quick question due to what you wrote:
&quot;Application scope functions can cause processing bottlenecks because the server can only execute one copy of the function at a time. All requests that require the function must wait their turn&quot;

Does this apply to Application scope CFC's?? Any Ideas?

As for using UDF's on Application.cfc I have been having the same dilemas. Where to put them? I actually implemented your option 2. However, with the Textus Framework I don't worry about it anymore.


Sean Corfield
&quot;Application scope functions can cause processing bottlenecks because the server can only execute one copy of the function at a time.&quot;

This is complete and utter nonsense. It was a mistake in the 6.1 docs that was corrected in the 7.0 docs:

http://livedocs.macromedia.com/coldfusion/7/htmldocs/00001016.htm

Note that it specifically says access to UDFs in application scope is multithreaded!

As for the onRequest() method, I'd be curious how you would expect to deal with your UDF library in existing code for Web Service / Flash Remoting / Event Gateway calls to CFCs? (since those are the only cases that are adversely affected by the presence of onRequest())


Brian Rinaldi
Obviously, you are correct Sean...my mistake, I was mistakenly referencing the 6.1 docs on scoping UDFs and I didn't see the comment below on LiveDocs. I will make a correction note in the post so as not to unintentionally mislead anyone.

As for how to resolve this best, I am still only beginning to try Application.cfc and was trying to determine how this would affect my practice of including UDF libraries sitewide. There didn't seem to be any clear best practice in this regard and the fact that it couldn't be included in onRequestStart isn't obvious unless you read the documentation for that method. I am not clear on what you are saying would actually be the proper solution here? use onRequest?


Sean Corfield
Brian, I don't have any &quot;global&quot; UDF libraries - I tend to include a single UDF wherever I need it. However, yes, onRequest() is the right place to do this if you are migrating legacy code.

My question still stands: how do you deal with a global UDF library today (i.e., using Application.cfm) for CFCs invoked via Web Services and Flash Remoting? Once you answer that, I'll give an opinion on how to handle that for Application.cfc.

As for onRequest() intercepting Web Service / Flash Remoting / Event Gateway CFC invocations, there are many ways around this, depending on what you are really trying to do. You can put the CFCs in a separate directory with its own Application.cfc (that doesn't have the onRequest() method). Or you can have the onRequestStart() method look at the targetPage argument and, if it ends with &quot;.cfc&quot;, it can structDelete(variables,&quot;onRequest&quot;) and structDelete(this,&quot;onRequest&quot;) (I originated that workaround and a few people have blogged it). Again, it depends on what your onRequest() method does and how that plays with your Web Service / Flash Remoting / Event Gateway CFCs.


Brian Rinaldi
Thanks for the info Sean. As for your question, in the past (as in when using application.cfm) my UDF library didn't apply to CFCs invoked via Web Services and Flash Remoting as those didn't usually reside in the same directory. I would include UDFs in those cases on an as-needed basis. I would prefer to keep things that way, but in this case I don't have control over who puts what where in this application...meaning, another developer could stick a remoting cfc under the site root without my knowing (and yes, there should be better control of that, but I don't really have the authority to institute that although I have recommended it). I think your workaround would work perfectly for that scenario.


Sean Corfield
You could enforce the placement of Web Service CFCs etc by having onRequestStart() throw an exception if the targetPage ends in &quot;.cfc&quot; :) Then other developers would have to place such CFCs in the right place...


Forb
Thanks for the info


Laurent
i wanted to go with the first option, but it doesn't work for me...

all i get is: Variable QUERYSTRINGDELETEVAR is undefined when i try one of the included udfs


Write your comment



(it will not be displayed)