Ask a Jedi: AjaxProxy and Application Scoped CFCs

Paul asks:

I am working with CF8 and cfajaxproxy. I have all of my cfc's in the application scope and they all have init functions that take the dsn as parameters. On a form that I have, I am using cfajaxproxy to allow a user to add a value to a 'type' drop down list and the functions to do this are in my cfcs that I put in the application scope with variables.dsn.

I want to do something like this:

This isn't working because the cfajaxproxy call returns an error saying that 'element dsn is undefined in variables'.

I had to revert using this: And changed the component to use application.dsn instead of variables.dsn

Is there anyway to tell cfajaxproxy to use the application scope component (tried some things to no avail)? Or am I going to have to create a interface/facade (cfc that hits the app scope cfc) to do this? But I'm thinking that even if I do this, I'm going to have to hard code the variables.dsn to be the value of appllication.dsn or just use application.dsn within this new component.

So Paul, you already have the right answer, a proxy CFC. But you do not need to hard code the DSN value at all. Let's look at a real, simple example. First I'll build the main CFC, Paris: <cfcomponent>

<cffunction name="init" access="public" returnType="paris" output="false"> <cfargument name="dsn" type="string" required="true"> <cfset variables.dsn = arguments.dsn> <cfreturn this> </cffunction>

<cffunction name="getBooks" access="public" returntype="query" output="false"> <cfset var q = ""> <cfquery name="q" datasource="#variables.dsn#"> select id, title from books </cfquery> <cfreturn q> </cffunction>

</cfcomponent>

This CFC is then set into the Application scope via onApplicationStart():

<cfset application.dsn = "tmz"> <cfset application.paris = createObject("component", "paris").init(application.dsn)>

So far so good. Now what would the proxy CFC look like? First off it is important where you place the proxy CFC. In order for the Ajax-based controls to use them, they must be under web root. Your main CFCs can be anywhere - but the proxies must be web accessible. Let's build a simple proxy component to integrate with Paris' getBooks() method:

<cfcomponent output="false">

<cffunction name="getBooks" access="remote" returnType="query" returnFormat="json" output="false"> <cfreturn application.paris.getBooks()> </cffunction>

</cfcomponent>

Some things to note. The method is marked remote. Without that, I wouldn't be able to run the method even if it was under web root. I also went ahead and supplied a returnFormat. ColdFusion's Ajax controls will do this for me, but it doesn't hurt to specify it here as well. Then I just hit the Application scoped CFC. Note that I'm not worrying about the DSN setting.

I can see one possible thing here that could concern you. Imagine your proxy grows rather large and you have quite a few methods. Now imagine all of a sudden you changed the Application variable "paris" to "parisCFC". All of those methods would then break. You could get around this by adding a utility method:

<cfcomponent output="false">

<cffunction name="getBooks" access="remote" returnType="query" returnFormat="json" output="false"> <cfreturn getParis().getBooks()> </cffunction>

<cffunction name="getParis" access="private" output="false"> <cfreturn application.paris> </cffunction>

</cfcomponent>

In this sample, I added a method named getParis. Any method that needs Paris would simply call that first, and then call the method, as you see in getBooks above. I also marked getParis private since it doesn't make sense to remotely expose that.

Archived Comments

Comment 1 by Paul posted on 1/23/2008 at 4:14 AM

Thanks for the reply. I ended up setting a variable in the proxy cfc to be the object of the cfc that i wanted to call the functions from:

variables.itemManager=createObject("component", "itemManager").init(APPLICATION.dsn);

then i wrote functions in the proxy cfc like this:
<cffunction access="remote" name="getAllItemTypes" returntype="query" output="true">
<cfreturn variables.itemManager.getAllItemTypes() /> </cffunction>

What do you and others think?

Comment 2 by Tom Chiverton posted on 1/23/2008 at 4:28 PM

I think that if you have more than a handful of remote methods, you should
a) look at ColdSpring/LightWire for managering your dependancies and properties
b) look at AOP-like solutions, such as ColdSpring's RemoteFactoryBean for writing the proxy 'service' CFC for you.

Comment 3 by Simon posted on 3/20/2008 at 5:33 PM

Hi Ray,

I have set up a quick demo app just like above, I have a proxy CFC that talks to the application scoped object (well that’s the idea), but when I hit the application scoped object inside the proxy cfc I get the cf error "Element DBACCESS is undefined in a Java object of type class" etc... I can't for the life of me see whats going on here. I can send you the sample files if you want. Are there any settings I need to enable to allow the proxy CFC to access application scoped objects? This is driving me mad. Here is the simple proxy function call

<!--- Get array of media types --->
<cffunction name="getMedia" access="remote" returnType="array">

<cfreturn application.dbAccess.getMedia()/>
</cffunction>

I am setting up the application scoped object like this in the application.cfc

<cfset application.dbAccess = createObject("component","model.dbaccess").init(dsn='cfartgallery')/>

Comment 4 by Raymond Camden posted on 3/20/2008 at 7:25 PM

You are using application.dbAccess, and it doesn't exist. Your code needs to create this value somehow, somehwere. I can't say exactly how as I don't know the rest of your code.

Comment 5 by Simon posted on 3/20/2008 at 8:38 PM

Ray,

I am creating the application.dbaccess object in the onApplicationStart() in my application.cfc using this line

<cfset application.dbAccess = createObject("component","model.dbaccess").init(dsn='cfartgallery')/>

I'm i doing something really stupid here an just can't see it

Cheers

Simon

Comment 6 by Raymond Camden posted on 3/20/2008 at 8:40 PM

Is your CFC under the same folder that your Application.cfc is in?

Comment 7 by summer posted on 8/5/2010 at 12:56 AM

I'm getting the same problem that Simon had. Any resolution?

Comment 8 by Raymond Camden posted on 8/5/2010 at 2:52 AM

Can you show (via pastebin) your Application.cfc?