Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with:

Making Sure Your ColdFusion Applications Are Uniquely Named

By Ben Nadel on
Tags: ColdFusion

Making sure that your ColdFusion applications are uniquely named is crucial to proper application performance. If you have two ColdFusion applications that accidentally have the same name on the same instance, you'll get all kinds of weird, unexpected problems - variables not existing, wrong file paths, missing components, seemingly nonsensical settings. As such, it is very important that you pick unique application names. To make this decision easy (coming up with unique names requires too much thinking), I tend to use a combination of the hash() and getCurrentTemplatePath() functions in my Application.cfc

Application.cfc

  • <cfcomponent
  • output="false"
  • hint="I define the application settings and event handlers.">
  •  
  • <!---
  • Define the application. By using the current template
  • path, we can ensure that our application name completely
  • unique across the entire server. By using the hash()
  • function, we make the name more friendly.
  • --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  •  
  •  
  • <cffunction
  • name="onRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="I execute the current request.">
  •  
  • <!--- Debug the application name. --->
  •  
  • Current Template Path:<br />
  • #getCurrentTemplatePath()#<br />
  •  
  • <br />
  •  
  • Hash Of Template Path:<br />
  • #hash( getCurrentTemplatePath() )#<br />
  •  
  • </cffunction>
  •  
  • </cfcomponent>

As you can see, the name of my application is a hash of the Application.cfc file path. Running this page gives us the following OnRequest() event handler output:

Current Template Path:
C:\Inetpub\wwwroot\kinky_solutions\testing\app_name\Application.cfc

Hash Of Template Path:
CCD265808736B8560B8DF72618673D04

The latter of the two outputs is what our application name becomes. Now, this might seem completely unreadable and meaningless to you; but, remember - you don't have to read it at all; the application name is used to associate your application with the ColdFusion memory space (including things like the APPLICATION scope and CFLogin functionality). As such, the uniqueness of the application name is of more importance than its meaningfulness to you.

By getting into the habit of using this approach to ColdFusion application name creation, I have found that I never have to worry about forgetting to properly name my application again. Since the getCurrentTemplatePath() function returns a value unique to the current Application.cfc file, the chances that its hash() will collide with another hash() are extremely small.

I know that a lot of you are already doing this in your ColdFusion applications; but, I just wanted to whip together this quick post so that I could refer back to it if it every came up in a conversation or in another Coldfusion blog post. Also, if you aren't doing this, I would definitely recommend it - it has made my life a lot easier to debug.




Reader Comments

@John,

It's an approach that I happen to love! Once I figured this out, I pretty much stopped doing anything else. Unless you have a setup where it is important for two Application.cfc's to share the same name (without extension), I find that this makes life very easy.

Reply to this Comment

I have been bit by duplicate application names a couple of times.

I appreciate you sharing this information. This looks like something that will make my life easier.

Reply to this Comment

I am using a very similar approach, in order to distinguish between several domains I add a cgi.HTTP_HOST to the hashed string, e.g. <cfset this.name = hash( getCurrentTemplatePath() & cgi.http_host ) />

This way the sessions on serveral domains using the same webroot aren't shared (e.g. website.com, website.at and website.it)

Reply to this Comment

I sometimes do have two separate apps that share an Application.cfc, typically an app and it's companion administrative app. I use ColdBox and the admin app is typically a package of handlers within the main app. Based on the cgi.http_host I set the default event in CB to either be the app default or the admin app default.

I figured out early on I was being bit by the separate apps with the same name bug (I did want them to run in different scopes) so I just included the http_host in the application name.

You could do the same in your hash.

Reply to this Comment

@Ben

Nice reminder. I would recommend adding cgi.server_name to the hash as well.

hash( getCurrentTemplatePath() & cgi.server_name )

This will ensure a unique name when using shared code base across multiple clients.

Reply to this Comment

Hi Ben,

If we do this, does it not cause more of a performance hit on the application because it doesn't already have the name cached somewhere?

Using a unique name like this will cause CF to look at it again and again wont it?

I really am not sure - newbie here, but please clarify if doing this could cause an overhead of some sort (quite possibly not but better safe than sorry).

Thanks for the tips though!

Mikey.

Reply to this Comment

Awesome Ben, thanks. I once forgot to set my application name and when I dumped my application scope I got every application scope within the shared hosting environment in a giant structure. Any idea if this still happens in CF9?

Reply to this Comment

I've never been bit by this with my internal apps for my day job, but I've been bit by it with my consulting gigs where the client tried to make two instances of the app on the same site/server (one for debugging/testing), and like you said, things just got weird.

Great idea.

Reply to this Comment

@Hansjoerg, @Sean, @Sumit,

My only concern with adding the host name / server name to the hash is that "www.bennadel.com" and "bennadel.com" will actually register as two different applications. I suppose if you include a redirect in your htaccess file or in the pseudo constructor of the Application.cfc, you'll prevent creating unnecessary application instances... but it's just something to be aware of.

Of course, if the different server names are truly different apps, then this is a perfect solution - just playing devil's advocate.

@Unibands,

There might be a *tiny* performance hit; but, considering that the Application.cfc component gets created for every single page request, the CFC instantiation cost is so great (comparatively) that the cost of running the hash() method is going to be a drop in the bucket.

@Kyle,

Hmm, that's a good question; I'm not sure - I'll have to check it out.

Reply to this Comment

@Joshua,

Exactly! And, it just seemed to breaking in insane ways before you realize what is going on. Talk about a good head-banging session :)

Reply to this Comment

@Ben,

Great point about domain name with and without "www". May be use a part of the domain name or some other unique identifier for shared codebase.

Reply to this Comment

Concerning domain name and the 'www'-prefix, you should always make sure to choose a canonical name for your site anyway for SEO reasons. So you'd better do a rewrite from .yourdomain to www.yourdomain or the other way round on the webserver level (using mod_rewrite if you're on Apache). This way you just don't run into problems like this.

Reply to this Comment

I've seen this approach taken before, but it's messy with a lot of things. Saying you don't have to read the name is not true.

For instance cflog writes the application name in the log file. As you somewhat mentioned CF also uses the application name to create the the full (server side) session Id, the cookies for cflogin, and also uses it in the database for client variables.

Debugging an application with a generated name is a real pain since the MD5 from hash() doesn't tell you anything. Where did these client variables come from? What application logged those entries? Who does this session belong to (in the server monitor)?

We name all our applications with reverse DNS instead, and then tack on the path to the application if it's nested replacing slashes with underscores since slashes aren't allowed in cookies and CF is dumb about it. This ensures uniqueness. (The reverse part being stylistic)

ex.
this.name = "com.cfunited.wiki_2009"

Once your server grows beyond a couple applications you'll appreciate this a lot. Especially in 2 years when it comes time to debug your server after it's grown to 20 applications instead of just a few!

Reply to this Comment

@Markus,

Agreed - both for SEO and Analytic's reasons.

@Elliott,

That makes sense. Logging is not something that I've dealt with too much and is something I wish I knew a bit more about. In CF9, I think the application name is also used from some of the caching (I can't remember, but I think I've seen huge, long names somewhere).

Reply to this Comment

@Markus,

What are your thoughts on "www" vs. no sub-domain? I always like "www", but purely for emotional reasons. I see when you to to Twitter, they always redirect you to the no-sub-domain version. Do you have any feelings on which is thought of more highly?

Reply to this Comment

@Ben The www. is really just noise, so if you're starting fresh with a new site I think it's best to use the plain domain name as your canonical hostname. Save your users some typing.

On the other hand if you've already got the www.-thing going for a while you may have lots of external links already using this, so to avoid getting spiders all confused and risk loosing link juice (though you _should_ be safe with a 301 redirect, but better safe than sorry), stick with it.

There may be other valid reasons for using the www-subdomain in specific cases, so your mileage may vary.

Reply to this Comment

@Markus,

Hmm, good point - I don't want to mess things up for existing "link juice" :) Going forward with new sites, though, I guess that makes sense as far as no need to have people type less.

Reply to this Comment

And as an afterthought: Even when you've decided to drop the www, you should still account for users who just type it in because they're just so used to this - so a redirect to your canonical is still a must.

Reply to this Comment

@Markus,

Yeah, agreed. As a side note to that, I've actually starting using some 301 redirects on my site for content that was accessible in different formats and it definitely had a noticeable impact on my analytics.

Reply to this Comment

@Ben Regarding this issue, a 301 may not always be the right solution to a certain duplicate content problem - and you need to be aware that even a 301 reply is still work for your webserver and two additional unnecessary HTTP requests.
There may be cases where you want some content rendered a little bit differently, controlled by maybe some URL-parameter(s) or some such thing. Or a forum overview page where you make use of visited-styles by appending the number of posts in a thread as a nonsensical URL-parameter to the thread-link.
In such cases you certainly do not want a 301 but just want to tell the spider that this is the same content as the one under a different URL.
In Google Webmaster Tools you can configure a couple of URL parameters for Google to ignore, but it's much more reliable and controllable if you use a <link rel="canonical" /> for such cases.

Reply to this Comment

@Markus,

My issues was that my site actually runs off action variables, but I have "pretty" URLs. So, for example, this blog post used to be accessible by it's ID alone:

index.cfm?dax=blog:1845.view

... or by it's pretty url:

/blog/1845-Making-Sure-Your....htm

I decided to only have the "view" available in pretty url format, so I 301 redirect the action variable version to the pretty URL version (and changed all internal links that used the action-variable version).

It seems that this has given me better analytics, but it could very well be coincidental.

I am not familiar with the <link rel="canonical" /> item. I'll have to look into that.

Reply to this Comment

@Ben It's definitely not a coincidence, this is exctly what you'd need to do when using SEO-URLs. We use a component that parses the URL and spits out a struct of action parameters in on method and another method which builds a pretty URL from the exact same parameters. Then we compare the actual current URL to the one we generated and decide what we should do then, the options being a 301 redirect, the <link rel="canonical"> or a <META NAME="ROBOTS" CONTENT="NOINDEX, FOLLOW"> in the <head>-section.
In order to actually get at the current URL from Apache, we use the following rewrite-rule:
RewriteRule (.*) /index.cfm?rewrite=$1&%{QUERY_STRING} [PT,L,env=REAL_URL:$1]
and then use the variable CGI.REDIRECT_REAL_URL in CF to get at the real current path.

Reply to this Comment

@Markus,

That's a slick idea - comparing the given URL to the one that *should* be generated. With my SEO urls, really all that matters is the ID at the beginning. This is nice because if a link gets cut off (wraps weird or something), people can typically still get to the page. But, I should probably compare the given URL to the one that *should* be there and then perhaps redirect to the full version.

Reply to this Comment

@Ben
What I mean (sorry, not clear in that post) is when you want to use two application.cfc files in the same application.

For example, a project i am working on now has an /admin/ directory with its own application settings, but also sharing some global values, using the same "this.name" value as the application.cfc in the root folder.

So, if I was to use the 'current template path' method, it would be a different hash value, i.e. two separate application names, for each application.cfc file.

Normally I just enter the same name in both files and make sure it is something unlikely to be duplicated on a shared environment. But I like your automated approach - just wondering if there's a similarly slick yet reliable (i.e. idiot-proof) method recommended for this type of application structure.

As a side note, is there any method in CF to find out if an application exists on the CF server? I.e. prevent duplicate names, or see if an application instance by a certain name has been created? This could theoretically be useful as well.

Reply to this Comment

@Michael,

Ah, I get exactly what you're saying now. The way to get around that that pops into my mind would be to extend the primary Application.cfc from within your secondary (admin) Application.cfc. Of course, then you can something like:

<cfcomponent extends="Application">

... which will definitely confuse the ColdFusion engine. Sean Corfield presented a nice solution for that problem a little while back:

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

It took me like 8 times reading that to finally get quite what he was saying (not his fault in any way), so if have any questions, please feel free to ask.

If you don't want to go the extend route, I am not sure there is going to be another elegant solution.

Reply to this Comment

I have a Stack Overflow question about extending Application.cfc.
You see: On our dev server, all our projects are in \inetpub\wwwroot\Projects\ProjectName.
Of course, on the clients' site, their individual projects are in \inetpub\wwwroot.

In the admin folder, I need to extend the ApplicationProxy that is one folder up, not the ApplicationProxy that is in the root.

One possible solution is to reverse the logic: have the top level Application.cfc extend the Application.cfc in the admin folder.

But I wish I could extend "../ApplicationProxy".

http://stackoverflow.com/questions/2015277/extend-application-cfc-but-not-from-the-root

Another possible solution is to use a lot of cfincludes inside both Application.cfc's, because cfincludes can use the ColdFusion mappings.

Reply to this Comment

@Phillip,

Yeah, extending the Application object is a bit more complicated than extending any other object because you cannot have per-application mappings. Definitely makes things a bit more interesting.

Reply to this Comment

@Ben

Thanks, I think I get it.

I'll give it a shot just for the sake of experimenting, but now i have to ask, is the small trouble to keep things set up with the empty 'proxy' file worth the small benefit of being able to auto-generate the application name. Hmm...

Reply to this Comment

@Michael,

It all comes down to what you're able to maintain. I ended up doing the auto-naming because I kept forgetting to create unique app names (a by-product of copy-n-paste application creation). If you are fine with it, there's nothing particularly beneficial about using this approach.

Reply to this Comment

I've run into a different issue with this Application stuff, and I don't think the hash is going to fix it.

I generate an application name using some uniqueness a little above the hash example above:

<CFOUTPUT>
<CFSET TempName=LEFT(REREPLACE(CGI.SERVER_NAME,"[^[:alnum:]]","","ALL"),50)>
<CFSET TempHost=LEFT(REREPLACE(CGI.REMOTE_ADDR,"[^[:alnum:]]","","ALL"),45)>
<CFSET AppName=LEFT(TRIM("SOMENAMEHERE#TempHost##TempName#"),40)>
</CFOUTPUT>
<CFAPPLICATION name="#AppName#"
clientmanagement="yes"
sessionmanagement="yes"
setclientcookies="yes"
setdomaincookies="yes"
sessiontimeout="#CreateTimeSpan(0,0,30,0)#"
applicationtimeout="#CreateTimeSpan(0,0,30,0)#"
loginStorage="session">

and using this is generally good until you get two people in the same room or same area who share an IP address and are working on the same application, such as you'd find in a class room. Then, they're all signed on with the same name, and if one signs off they all get signed off.

I'm thinking for best results we need to stuff a cookie with a guid or other variable and look for that on the machine that's running the system.

Or... is there a better way to ensure two machines don't share the same userid?

Reply to this Comment

Looking for inputs as to this as a solution to the unique app name I mentioned above:

<CFIF NOT ISDEFINED("COOKIE.myAppName")>
<CFOUTPUT>
<CFSET TempName=LEFT(REREPLACE(CGI.SERVER_NAME,"[^[:alnum:]]","","ALL"),50)>
<CFSET TempHost=LEFT(REREPLACE(CreateUUID(),"[^[:alnum:]]","","ALL"),45)>
<CFSET AppName=LEFT(TRIM("TMRMEMOBILE#TempHost##TempName#"),40)>
</CFOUTPUT>
<CFSET COOKIE.myAppName=AppName>
</CFIF>
<CFAPPLICATION name="#COOKIE.myAppName#"
clientmanagement="yes"
sessionmanagement="yes"
setclientcookies="yes"
setdomaincookies="yes"
sessiontimeout="#CreateTimeSpan(0,0,30,0)#"
applicationtimeout="#CreateTimeSpan(0,0,30,0)#"
loginStorage="session">

And when the person logs out, you would run something like this:

<CFSET xyz=StructDelete(cookie, 'myAppName')>

The problem I see, though, is when someone closes the browser and re-opens it, the cookie still exists if they did not sign off run the delete code.

Anyone have any suggestions on any of this?

Thanks!

Reply to this Comment

Here is another question about dynamic application name.
How can we run a query first and get an id from a table and set the application name adding a string and this id?
for example create an application name this.name=multisite_#query.uniqueid#

If this is not possible, can we change the application.name on session.start or is it a bad practice?

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.