GetPageContext.Include() DOES Parse Files And More (Thanks Charlie Arehart)
I was under the impression that when you included a template via the page context Include() method, the template was simply included as a text file.
<!--- Include page without parsing. --->
<cfset GetPageContext().Include( "./include.cfm" ) />
I touched upon this in my entry about reading in files using CFInclude. Charlie Arehart pointed out that this was, in fact, quite incorrect. He pointed out that not only does the included file get parsed by ColdFusion, is also gets treated as a regular page call complete with Application.cfc/cfm pre-page processing.
I believe him, but just to see it for myself, I set up a little test. First, I set up a simple Application.cfm template to help test pre-page processing. The Application.cfm simply defines the application and increments a page request counter:
<!--- Define application. --->
<cfapplication
name="CFInclude Test"
applicationtimeout="#CreateTimeSpan( 0, 0, 10, 0 )#"
/>
<!---
Param the counter to keep track of how many requests
run through the application page pre processing.
--->
<cfparam
name="APPLICATION.RequestCount"
type="numeric"
default="0"
/>
<!--- Add one to the request count. --->
<cfset APPLICATION.RequestCount = (APPLICATION.RequestCount + 1) />
Then, I set up a single page that including a template using both the traditional ColdFusion CFInclude tag as well as the GetPageContext().Include() methodology:
<!--- Write this main request to file. --->
<cffile
action="APPEND"
file="#ExpandPath( './trace.txt' )#"
output="Request #APPLICATION.RequestCount#"
addnewline="true"
fixnewline="true"
/>
<!--- Include file. --->
<cfinclude template="include.cfm" />
<!--- Include file. --->
<cfset GetPageContext().Include( "include.cfm" ) />
As you can see, I am tracing my page request to a text file, trace.txt. This way I can see which page request each include is being part of. Then I have the simple include.cfm template:
<!---
Figure out if we are running the CFInclude version of
this template. Check the base tag list to determine what
text we should output.
--->
<cfif ListFind( GetBaseTagList(), "CFINCLUDE" )>
<!--- Set mode text. --->
<cfset strMode = "CFInclude" />
<cfelse>
<!--- Set mode text. --->
<cfset strMode = "Include()" />
</cfif>
<!--- Try to write this request to file. --->
<cffile
action="APPEND"
file="#ExpandPath( './trace.txt' )#"
output="...Included via #strMode# during request #APPLICATION.RequestCount#"
addnewline="true"
fixnewline="true"
/>
As you can see, I am using the base tag list to determine which methodology was used to include the current tag. If the base tag list contains CFINCLUDE, then I know that I am using the standard ColdFusion CFInclude tag. If not, then I know that I am using the GetPageContext().Include() methodology.
By my previous assumptions, the GetPageContext().Include() methodology should not even write to the trace file since it is not being parsed. However, when I looked at the trace file, I get something very different:
Request 38
...Included via CFInclude during request 38
...Included via Include() during request 39
Request 40
...Included via CFInclude during request 40
...Included via Include() during request 41
Request 42
...Included via CFInclude during request 42
...Included via Include() during request 43
Request 44
...Included via CFInclude during request 44
...Included via Include() during request 45
I was completely wrong. And, it looks like Charlie Arehart was dead on the money. As you can see, the template, when operating under a ColdFusion CFInclude tag, runs in the same page request as its parent template. However, as you can see by the APPLIACTION.RequestCount output, the include, when included via the page context not only outputs to the trace file, indicating that it does in fact get parsed, it is also incrementing the APPLIACTION.RequestCount variable indicating that it does in fact get treated as its own page request (complete with pre-page processing).
This is some very good information to know. Sorry to all of you out there that I mislead about the page context Include() method. Thanks Charlie for showing me the light - you the man (this is adding to your existing man-factor acquired via your CFHttp / CGI variable comments back in 2004)
I also noticed that at the bottom of my page I was getting a 500 null error. Ugg, the dreaded 500 null error! I can only assume that this is happening because I am including one page request inside of another and come one people, that just doesn't make any sense - why would I do that??
Want to use code from this post? Check out the license.
Reader Comments
Glad to help, Ben. :-) As with that other entry (and all my contributions), I just enjoy sharing what I've learned, whether on my own or from this great CFML community. Cheers.
Charlie,
Always appreciated. Hey, do you have any ideas why using the Include() method would cause a 500 null error? The page was include successfully and the rest of the calling page executes. I definitely get content written to the buffer post-Include()... but no matter what I do, I can't seem to get the 500 null from showing up at the bottom of the page.
Any ideas? Thanks.
No, Ben, sorry. I'm afraid I don't. If you can't find an answer elsewhere, if you get a chance, try it on BlueDragon (which supports the getpagecontext function as well). If you get the 500 there, you could ask on the BlueDragon intere4st list (free support from BD engineers). I'm traveling and have very limited connectivity so can't investigate that for you further right now. Sorry. Good luck with it, and I'll look forward to any answer you find.
Hi there,
I also am getting the "500 null" error message when using the include() method.
I am using this method to have the included files' Application.cfm template execute as well as the included file, however the error message is spoiling the output despite the include having been cosmetically successful.
Any ideas?
Ethan Cane
Web Developer
Here is the error message I get as part of the 500 null error message:
19/02 03:09:40 error
java.lang.NullPointerException
at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:59)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:115)
at coldfusion.CfmServlet.service(CfmServlet.java:107)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:78)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:91)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:257)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:541)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:204)
at jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:318)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:426)
at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:264)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
EOF
Ethan Cane
Web Developer
Ethan,
I am curious... if you are using the Include() method to include the Application.cfm file, what file houses the Include() method? The Application.cfm file should get called automatically when any CFM file in the folder or sub folder gets called.
My guess is that you CANNOT Include() the Application.cfm. Just as you cannot call the Application.cfm file directly, Include() will probably throw a fit in the same vein.
I think what Ethan meant is that he's using the Include method to call a CFM template (instead of using CFINCLUDE) so that the execution of that page causes the application.cfm to fire. As such, I'm not sensing he's doing it to include the application.cfm itself, but rather indirectly.
That said, I still don't know what the 500 error is about.
But as I read your reply, Ben, it did make me wonder if it's at all possible (Ethan) if your application.cfm does indeed do anything that would somehow cause the execution you're attempting to, in effect, loop. For instance, if the application.cfm itself did an include of the desired page (or another application.cfm at a higher level, perhaps) or if the page being called included itself somehow, I could see that causing a 500 error.
I have run into random 500 null errors that are seemingly impossible to debug when using things like Include() and Forward() methods. I usually cannot figure them out as they provide almost no insight, and in some cases do not seem to stop anything from working (other than putting a 500 null at the end of the page).
@Ethan,
If you give us a bit more info about what is going on, we can help debug, or come up with an alternate solution that does not require Include().
Hello all,
Firstly thanks to everyone for contributing to this post.
What I am trying to accomplish is to multihome websites on a shared hositng account.
I already have the domain name xmlstandards.org and have just aquired several other domain names for development purposes.
Presently the xmlstandards.org hosting account can make use of both ColdFusion MX 7.02 and PHP 5.x scripting capabilities.
Since my hosting provider (HostMySite) does not offer multihoming on a shared setup I thought instead of using ColdFusion <cfswitch/> statement to perform a server-side redirect based upon the CGI.HTTP_HOST variable.
With this information in pocket I would be able to re-organize my sole "htdocs" DOCUMENT_ROOT to contain one folder for xmlstandards.org and another for each newly aquired domain (eg: new-domain.org).
Withing the DOCUMENT_ROOT I would then have a single index.cfm template (let's call this template a domain driver for arguments sake) which would redirect a user based upon the domain name entered into the address bar of their browser (aka HTTP_HOST).
The basic outlay of the "htdocs/index.cfm" would be a switch statement that would check for the CGI.HTTP_HOST variable and if the case is true then the following code would execute.
<cfset GetPageContext().include("/xmlstandards.org/index.cfm")/>
Using the above code snippet I would have expected (from previous readings) that the primary ("/htdocs/index.cfm") would then include the index.cfm template from the xmlstandards.org sibling folder.
This would allow me to present content that would be solely specific to that associated domain name (XML stuff). Behind the scenes however, I learned that one of the main benefits of using such a mehthod to perform an include is that the Application.cfm template associated at the same level as the included template is also incorporated into the overall page processeing.
This is why I have chosen to use the GetPageContext().include() method as opposed to using the more generic <cfinclude template="index.cfm"/> method. Using this method does not incorporat e the associated Application.cfm.
OK.
So with that out of the way, I was pleased to find that my readings were indeed well spent and that the associated Application.cfm template could set its own variable assignments and these could be referenced successfully from the domain specific index.cfm. Switching domains successfully present content specific to each domain. So all is well there.
However, I originally tested this on a development server before testing against production setup. My development box had debugging enable (both robust exception handling and the other option to simply enable debugging of more developer centric output).
It is with the developer-centric debugging enabled that the 500 null error message is displayed at the bottom of the output.
This was easily enough remedied by disabling debugging output altogether and the error 500 null no longer appeared, however since the whole process of template inclusion seems to have occurred without any major hitch, what gives with the error message?
I did read about an existing bug on Adobe about the license.properties file ($CFMX_HOME/lib/license.properties) sometimes casuing this to occur of the file has for some reason become zeroed out. (ie. file size is "0"), however my license.properties file is fine and in good order.
OK. So to wrap up...
I have the code I want working to a degree, it is just the presence of the error message that causes concern when porting such code to a production system.
PS.
If anyone knows of a better method to employ ColdFusion to perform domain name switching on shared hosting setup, then let me know.
The only main drawback is that pages only work if they are at the same level. I cannot nested any deeper or links will break. Any ideas would be appreciated.
Many thank all for listening.
Regards
Ethan Cane
Web Developer
PPS. Watching The Adventures of Sherlock Holmes and drinking London Pride ale in my penthouse flat in North London running Linux.
It really doesn't get much better than that!
Ethan,
What you are doing sounds very cool. And unfortunately, I do not have any great advices to offer you. The 500 null error is such a bastard to track down and can be caused by sooo many different things (I find).
What are you doing after the Include() method gets called? Perhaps what is happening is that the "included" page runs and all the application event methods fire off... then the calling page (root page) ends its processing and this causes conflicts.
What page is actually calling this? Is it the root Application.cfm. Sorry if you discussed this in your comment (I did not understand 100%). Maybe try a CFAbort after the Include(). See if that makes a difference.
Sorry I do not have the answers :(
Hi Ben,
Thanks for sticking with me on this one.
I have not tried just yet, but I think you might be right and that the addition of a <cfabort/> would solve the issue.
Will test it out and get back to you.
Ethan Cane
Web Developer
Ethan,
Yeah, keep us updated. Be aware though that CFAbort, I think, technically throws an error as well (just the nature of what CFAbort is). I am not sure if there is a better way to halt processing.
HI!
I also am getting the "500 null" error message when using the include() method.
Interesting. So GetPageContext.Include() must have an overhead in comparison to CFINCLUDE.
My only need for GetPageContext.Include() has been security - If you don't want the included template to be parsed, change the extension to .htm and include it with GetPageContext.Include(). It works beatifully. I wonder how it would behave if you try to include a PHP file. Has anyone tried that?
@reazon -- it used to be (not sure about now) that files included with cfinclude that had a .htm extension would still be treated almost if not identically to files with a .cfm extension. I worked at a company where one of the other developers had decided to make all their include files have a .inc extension, so you could go to them directly in a browser and view the source (obvious security botch), but when they were included they behaved just like any other cfm...
They also had a bunch of .zml files, but those had been added to the ISAPI engine so that IIS would pass them to CF for parsing... I would expect that getPageContext.include() works the same way -- doesn't matter what the extension is by virtue of the fact that you happened to pass the file to it... The only way to get it to not parse the file is to not pass the file to it, like IIS didn't pass the .inc files.
But then in the past it's been at least semi-popular to add .htm to the list of extensions parsed by CF so that you can have your whole site in .htm files and it not matter which technology you're using underneath -- so if you were to ever switch say from CF to ASP or PHP, none of your links would change. And that also means you can never be too sure that a .htm won't be parsed -- or for that matter .js or .css and I believe I actually have some code in my Application.cfc for the onTap framework that checks the extension of the base template for precisely that reason - so that it will let you have css or js files if someone assigned them to CF ... speaking of which, I'm not sure if that code even works as expected because I don't think I ever tested it and in retrospect, the framework may choke since it doesn't include the requested file and abort early. Oh well... it's an extreme edge case. :)