Coldfusion Element DSN is undefined in REQUEST(Coldfusion 10)

1.7k Views Asked by At

OK so for some odd reason the request.dsn and another variable I created called request.cfcDIR are not being kept once set in the Application.cfm file.(Coldfusion 10)

Here is where the values for the two above variables originate from.

<cfset chkURL = "#CGI.HTTP_HOST#">
<cfif ((chkURL) EQ "url.subdomain.here" OR (chkURL) EQ "url.subdomain.here.a" OR (chkURL) EQ "url.subdomain.here.b" OR (chkURL) EQ "url.subdomain.here.c")>
  <cfset whichDB = "1,2,3,4,5,6">
<cfelse>
  <cfset whichDB = "0">
</cfif>

<!--- Start Check for Which DB the user resides and overwrite the request.dsn variable in Application.cfm --->
<cfif ((whichDB) NEQ 0 OR (whichDB) NEQ "")>
<cfset whichDB = "#whichDB#">
 <cfif (whichDB) EQ 0>
      <cfset request.dsn = "xxxxx_1">
  <cfelse>
      <!--- Loop through the whichDB list --->
      <cfloop list="#whichDB#" delimiters="," index="i">
          <cfquery name="CheckDB" datasource="xxxxx_#i#">
            Select username,db,compid
            FROM users
            WHERE username = <cfqueryparam value="#FORM.username#" cfsqltype="cf_sql_varchar" maxlength="20">
          </cfquery>
           <!--- Here we check for which database has the results which originates from the Query(CheckDB) above
          ***IMPORTANT*** in order for this to work properly your Coldfusion DSN must named xxxxx_1, xxxxx_2 and so on...--->
           <cfif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 1>
               <cfset client.dsn = "xxxxx_1">
               <cfset client.cfcDIR = "cfcV5">
               <cfset request.dsn = "xxxxx_1">
               <cfset request.cfcDIR = "cfcV5">
               <cfbreak/>
           <cfelseif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 2>
               <cfset client.dsn = "xxxxx_2">
               <cfset client.cfcDIR = "cfc">
               <cfset request.dsn = "xxxxx_2">
               <cfset request.cfcDIR = "cfc">
               <cfbreak/>
           <cfelseif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 3>
               <cfset client.dsn = "xxxxx_3">
               <cfset client.cfcDIR = "cfcV5">
               <cfset request.dsn = "xxxxx_3">
               <cfset request.cfcDIR = "cfcV5">
               <cfbreak/>
           <cfelseif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 4>
               <cfset client.dsn = "xxxxx_4">
               <cfset client.cfcDIR = "cfc">
               <cfset request.dsn = "xxxxx_4">
               <cfset request.cfcDIR = "cfc">
               <cfbreak/>
           <cfelseif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 5>
               <cfset client.dsn = "xxxxx_5">
               <cfset client.cfcDIR = "cfcV5">
               <cfset request.dsn = "xxxxx_5">
               <cfset request.cfcDIR = "cfcV5">
               <cfbreak/>
           <cfelseif (CheckDB.RecordCount) NEQ 0  AND (CheckDB.db) EQ 6>
               <cfset client.dsn = "xxxxx_6">
               <cfset client.cfcDIR = "cfcV5">
               <cfset request.dsn = "xxxxx_6">
               <cfset request.cfcDIR = "cfcV5">
               <cfbreak/>
           <cfelse>
               <cfset request.dsn = "xxxxx_1">
           </cfif>
        </cfloop>
    </cfif>
</cfif>

So the above code works fine as the Application.cfm gets the set variables. However the request.dsn does not stick, is as if I never defined it in the first place. Just to be safe I defined the variables twice in the code above.

Here is what the Application.cfm file looks like.

<cfapplication name="Appname-here"
    sessionmanagement="yes"
    clientstorage="cookie"
    clientmanagement="Yes"
    loginstorage="session"
    scriptprotect="all"
    sessionTimeout = #CreateTimeSpan(0, 0, 10, 0)#>
<cfswitch expression="#CGI.HTTP_HOST#">
   <cfcase value="url.subdomain.here">
      <cfif IsDefined("request.dsn")>
        <cfset request.dsn = '#client.dsn#'>
      </cfif>
      <cfset request.cfcDIR = #client.cfcDIR#>
   </cfcase>
   <cfdefaultcase>
      <cfset request.dsn = 'xxxxx_1'>
      <cfset request.cfcDIR = cfcV5>
   <cfdefaultcase>
</cfswitch>

So when the user moves on to the define user page to land on I get an error stating that "Element DSN is undefined in REQUEST" which is bullshit because is being defined.(Coldfusion 10)

2

There are 2 best solutions below

2
On

Here's what I would suggest. For each case statement in Application.cfm, simply declare the dsn, as follows:

<cfcase value="url.subdomain.here">
  <cfset request.dsn = 'dsnForThisSubdomain'>
  <cfset request.cfcDIR = 'cfcDirForThisSubdomain'>
</cfcase>

Application.cfm code will always be run first, on every request. You can't reference vars set in code that will run later in Application.cfc in this way. That's why I'm suggesting that if there is a one to one relationship between subdomain and the request vars you need, just set them here.

Note that you can place multiple subdomains as a list in your case statements, so you can have:

<cfcase value="url.subdomain1.here, url.subdomain2.here">
  <cfset request.dsn = 'dsnForThisSubdomain'>
  <cfset request.cfcDIR = 'cfcDirForThisSubdomain'>
</cfcase>

If that won't work for you, you need to clean up some errors and misunderstandings in your code. First:

<!--- Start Check for Which DB the user resides and overwrite the request.dsn variable in Application.cfm --->

At this point, you cannot overwrite the request.dsn variable. It's too late for that in the request lifecycle. Your assumption that you can is a fatal flaw. Beyond that:

Instead of

<cfif ((whichDB) NEQ 0 OR (whichDB) NEQ "")>

I suggest using

<cfif whichDB > 0>

Which makes your intention much more clear

<cfset whichDB = "#whichDB#">

The above cfset simply assigns the value of the whichDB to itself, which you don't need to do. You also never need to dereference a var to set it. So even tho' it's useless, the correct way to write this would be:

<cfset whichDB = whichDB>

Following that line, you have

<cfif (whichDB) EQ 0>

Which will never be run, because it is nested inside

<cfif ((whichDB) NEQ 0 OR (whichDB) NEQ "")>

So the code in that if branch should be moved. You could put it near the top, under <cfset whichDB = "0"> at line 5 of your code block.

As to the rest of it, <cfbreak/> isn't needed at the end of an if or elseif block. Your code might be cleaner here if you used a cfswitch block instead of multiple elseif blocks, and I'd suggest using session scoped vars instead of a client scoped vars. Something like:

<cfif CheckDB.RecordCount>
    <cfswitch expression="#CheckDB.db#">
        <cfcase value="1">
            <cfset session.dsn = "xxxxx_1">
            <cfset session.cfcDIR = "cfcV5">
        </cfcase>
       ...

    </cfswitch
</cfif>

At this point, I'd suggest running a search and replace on your code base and change request.dsn to session.dsn and request.cfcDIR to session.cfcDIR, and forget about setting request vars in your Application.cfm file if the session vars exist. There's no value to maintaining 2 variables for the same thing in your app. But if you decide to do this anyway, you must get the logic correct in your Application.cfm - you have it backwards now. Best would be:

<cfif structkeyexists( session, 'dsn' )>
    <cfset request.dsn = session.dsn >
</cfif>

and you also need a similar if statement around the cfset for session.cfcDIR, which you have a client.cfcDIR, because it will not exist before the user logs in, and hence will throw an error.

3
On

The "Request scope" exists for the life of a single request . Unless there is something above your <cfapplication ...> tag, the line that says:

<cfif IsDefined("request.dsn")>
        <cfset request.dsn = '#client.dsn#'>
      </cfif>

... will never trigger (will never return true).

If you want to check a Request variable, then you will need to require that it be set or have the code that requires it happen before the check. It only exists until the end of the request. Your client var will persist however. Perhaps you meant:

<cfif IsDefined("client.dsn")>
        <cfset request.dsn = '#client.dsn#'>
      </cfif>

That would make more sense to me.


ADDITIONAL INFO

Reya - your problem is still what you see below in my answer. You will need to set your request variable with every request meaning every time the user clicks on something or loads something that causes and http call to your server. It will need to be set before the call to your cfapplication where you check for it.

If I could suggest an architectural change, in your login script, figure out what database the user belongs to and then set it in the session scope. Then alter your "datasource" attribute to #session.dsn" - or of course you could use the "client.dsn" - but that too would require the change above.

So you will either need to use a persistent scope (session or client probably) or run code to set the request scope prior to the code in the application file you have pasted above. I know I'm having a hard time making it clear. :)