Code Bank
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
 
 
User Name:
Password:
Remember me
Go Back   ASP Free ForumsProgrammingCode Bank

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread ASP Free Forums Sponsor:
  #1  
Old March 11th, 2006, 12:55 PM
Rust Indy Rust Indy is offline
Contributing User
ASP Free Newbie (0 - 499 posts)
 
Join Date: Mar 2006
Posts: 31 Rust Indy User rank is Private First Class (20 - 50 Reputation Level)Rust Indy User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 12 h 41 m 14 sec
Reputation Power: 3
Executing Dynamically Included ASP

We've all hit a point sometime where we've wanted #include a file with a dynamic name, or with querystrings attached, or maybe even include different files based on an If..Then or Select Case block. Perhaps you've even wanted to create a plug-in architecture for your website that would load plugins automatically.

And as we've all found, this is next to impossible with ASP. But here's the code to make it work:

asp Code:
Original - asp Code
  1. sub include(sFile)
  2.  dim mfo, mf, sTemp
  3.  set mfo = Server.CreateObject("Scripting.FileSystemObject")
  4.  set mf = mfo.OpenTextFile(sFile, 1, false, -2)
  5.  sTemp = mf.ReadAll
  6.  mf.close
  7.  set mfo = nothing
  8.  ' The following two If..Then blocks will remove the ASP tags from the beginning and end of the file, if they exist
  9.  if left(sTemp, 2) = "<" & "%" then
  10.   sTemp = right(sTemp, len(sTemp) - 2)
  11.  end if
  12.  if right(sTemp, 2) = "%" & ">" then
  13.   sTemp = left(sTemp, len(sTemp) - 2)
  14.  end if
  15.  ExecuteGlobal sTemp
  16. end sub


So what does this code do? Essentially, it simply reads the file passed in the "sFile" variable, stripping the ASP tags from the beginning and end, and then executes the remaining code. This will allow you to write dynamically included files that contain functions, subs, classes - whatever you like.

To use this function, just call it from your code with a complete physical path - like
Code:
include "c:\inetpub\wwwroot\mysite\filename.asp"

Obviously, since the filename parameter can be a variable, you can also simply loop through all the files in a "/plugins" folder (for example) and include them all dynamically at runtime.

The only drawback to this approach that I've noticed is that any errors that occur in the included files will be displayed as a file error on the "ExecuteGlobal" line of the subroutine. So far, I haven't found a way around that, so make sure your code works before including it this way. Use a regular #include during the development process, then switch to dynamic when the code is working.

For those concerned about speed, I haven't noticed any serious drop in performance on the site I used this technique on. Any given page will be dynamically including a minimum of 5 ASP files (mostly just Class blocks in these files, though one contains a number of functions), and the page still generates in about 0.005 seconds (yes, 0.005 seconds) after removing the database code.

Last edited by Rust Indy : April 9th, 2006 at 06:05 PM. Reason: Title change

Reply With Quote
  #2  
Old March 11th, 2006, 04:06 PM
Shadow Wizard's Avatar
Shadow Wizard Shadow Wizard is offline
Moderator From Beyond
Click here for more information.
 
Join Date: Sep 2004
Location: Israel
Posts: 26,936 Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)  Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1
Time spent in forums: 3 Months 1 Week 5 Days 11 h 28 m
Reputation Power: 1537
since IIS 5.0 there is the Server.Execute method that does pretty much the same.

Reply With Quote
  #3  
Old March 11th, 2006, 06:06 PM
Rust Indy Rust Indy is offline
Contributing User
ASP Free Newbie (0 - 499 posts)
 
Join Date: Mar 2006
Posts: 31 Rust Indy User rank is Private First Class (20 - 50 Reputation Level)Rust Indy User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 12 h 41 m 14 sec
Reputation Power: 3
The Server.Execute method is ideal for transferring out of your currently executing script and into a new one, taking the Request collections with you (Querystring and Form). No variables can be transferred oustide of those means (except, obviously, session and application vars). And it does have it's uses (as in my URL rewriting code).

An example where Server.Execute would not be useful might be if you were writing a blog that needed to be able to use multiple databases. As a developer, you might put database specific code into a class for each DB, with identical methods and properties (for example, you might have "sql2k.asp" and "mysql5.asp" and "postgres.asp", each containing a "Class Database" block). In your blog-engine code, you simply create a new Database class and use it - the engine doesn't care what type of DB it is, so you can *only* include the class file for the database you want to use. You can't use #include, you'll get an error about redefining a class name, even if you wrap an If..Else or Select Case block around your #include statements. You can't use Server.Transfer, your application will simply stop executing (unless you Server.Transfer back to the calling ASP page, which will create an infinite transfer loop). The Server.Execute function will likewise fail here since the class will be destroyed as soon as control is passed back to the calling script. You *could* use different class names in those files. Or you *could* just include() the one you wanted, based on the user's preference.

The same goes for a web app that has plugin capability. Instead of requiring the site maintainer (who is generally not the site coder) to modify a file with a new #include line, you can just have them place the plugin in a "/plugins" folder. Any ASP file in the plugins folder can then be dynamically included into the web application without any extra typing or additional points of failure. Another case where Server.Transfer is useless.

So yes, Server.Transfer does have it's uses, but dynamic includes is not really one of them. In my opinion, natch. Server.Transfer is simply a server-side redirection, not much unlike a browser-side redirection via Response.Redirect.

Reply With Quote
  #4  
Old March 12th, 2006, 02:18 AM
Shadow Wizard's Avatar
Shadow Wizard Shadow Wizard is offline
Moderator From Beyond
Click here for more information.
 
Join Date: Sep 2004
Location: Israel
Posts: 26,936 Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)  Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1
Time spent in forums: 3 Months 1 Week 5 Days 11 h 28 m
Reputation Power: 1537
I was refering to Server.Execute, not Server.Transfer that indeed has nothing
to do with including.
however you're correct about "class will be destroyed as soon as control is
passed back to the calling script" - in this, Server.Execute is different from
SSI and your code indeed solve this.
cheers yet again, keep it coming!

Reply With Quote
  #5  
Old March 12th, 2006, 02:41 AM
Rust Indy Rust Indy is offline
Contributing User
ASP Free Newbie (0 - 499 posts)
 
Join Date: Mar 2006
Posts: 31 Rust Indy User rank is Private First Class (20 - 50 Reputation Level)Rust Indy User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 12 h 41 m 14 sec
Reputation Power: 3
LOL, sorry about that, I got confused while I was typing

Server.Execute is also scope-specific, so my example of losing a class would never occur since a class cannot be defined from within a function, sub, or property of any kind. Theoretically, the class would remain as long as Server.Execute was called from root script (i.e. not within a function or sub or property).

But it didn't work for me ExecuteGlobal forces the equivalent of page-scope, as opposed to function or class scope

Reply With Quote
  #6  
Old March 12th, 2006, 04:03 AM
Shadow Wizard's Avatar
Shadow Wizard Shadow Wizard is offline
Moderator From Beyond
Click here for more information.
 
Join Date: Sep 2004
Location: Israel
Posts: 26,936 Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)  Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1
Time spent in forums: 3 Months 1 Week 5 Days 11 h 28 m
Reputation Power: 1537
I made simple test: page1.asp had Server.Execute("page2.asp") and in page2.asp
I had class MyClass - when I tried to create instance of MyClass in page1.asp
I got "undefined variable" which means you are correct.

Reply With Quote
  #7  
Old March 12th, 2006, 11:46 AM
Rust Indy Rust Indy is offline
Contributing User
ASP Free Newbie (0 - 499 posts)
 
Join Date: Mar 2006
Posts: 31 Rust Indy User rank is Private First Class (20 - 50 Reputation Level)Rust Indy User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 12 h 41 m 14 sec
Reputation Power: 3
Wow, I'd like to rewrite my previous two posts here, since I had totally confused myself

Server.Transfer: Redirects a user from one ASP script to another at the server, which doesn't require the browser to make a new page request like Response.Redirect does. Also doesn't affect the URL that the user types in, making it ideal for URL rewriting. Also preserves the Request.Form and Request.Querystring collections, but not variables or functions or classes defined in the first ASP file.

Server.Execute: executes and ASP page from within another ASP page. However, script variables and functions are not passed between the two pages, including the Request collections. You have to use querystrings or session or application vars to do that. Variables and functions/subs/classes created in one ASP file are not accessible to the other one.

Execute: executes any valid VBScript code within the scope of the page, function, sub or property that made the call.

ExecuteGlobal: executes any valid VBScript code in the global context, no matter what scope the call was made from.

So my dynamic include example could, theoretically, use the Execute command instead of ExecuteGlobal, but if the file you are dynamically including contains anything other than in-line script and variable/constant definitions, it must be called from outside of any other function, sub or property, limiting it's usefullness (since you cannot define a new function from within another function). Code that is executed via Execute is done in-place, just as if you typed it in right where the Execute call is being made.

I hope everyone (including myself) is clear on the different functionality now

Reply With Quote
  #8  
Old March 12th, 2006, 04:03 PM
Shadow Wizard's Avatar
Shadow Wizard Shadow Wizard is offline
Moderator From Beyond
Click here for more information.
 
Join Date: Sep 2004
Location: Israel
Posts: 26,936 Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)Shadow Wizard User rank is General 8th Grade (Above 100000 Reputation Level)  Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1Folding Points: 340465 Folding Title: Super Ultimate Folder - Level 1
Time spent in forums: 3 Months 1 Week 5 Days 11 h 28 m
Reputation Power: 1537
yes that's about as clear as it can be, thanks!

Reply With Quote
  #9  
Old April 2nd, 2006, 02:50 PM
Doug G Doug G is offline
Grumpier Old Moderator
ASP Free God 11th Plane (10000 - 10499 posts)
 
Join Date: Sep 2003
Posts: 10,143 Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level)Doug G User rank is First Lieutenant (10000 - 20000 Reputation Level) 
Time spent in forums: 3 Weeks 4 Days 21 h 28 m 48 sec
Reputation Power: 180
NOTE: This code is not the equivalent of #include and does not provide the same functionality. It's a good technique, but more appropriately this topic would be called "dynamic code execution".
__________________
======
Doug G
======
I didn't attend the funeral, but I sent a nice letter saying I approved of it. --Mark Twain

Reply With Quote
  #10  
Old April 2nd, 2006, 05:07 PM
Rust Indy Rust Indy is offline
Contributing User
ASP Free Newbie (0 - 499 posts)
 
Join Date: Mar 2006
Posts: 31 Rust Indy User rank is Private First Class (20 - 50 Reputation Level)Rust Indy User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 12 h 41 m 14 sec
Reputation Power: 3
If this topic was about ExecuteGlobal, then yes, this would be about dynamic code execution. But this thread is about a function that loads an arbitrary file and then executes the code within that file, which is, if I'm not completely mistaken, functionally equivalent to a dynamically included file. That this function makes use of ExecuteGlobal is incidental.

I'll even provide a nice example here to show that the functionality is there.

Your two existing files are "File1.asp"
asp Code:
Original - asp Code
  1. <%
  2. Response.Write "This is File1.asp<br />"
  3. %><!-- #include virtual="/File2.asp" --><%
  4. Response.Write function1
  5. Response.Write function2
  6.  
  7. function function1()
  8.  function1 = "This is a function in File1.asp<br />"
  9. end function
  10. %>

And "File2.asp"
asp Code:
Original - asp Code
  1. <%
  2. Response.Write "This is File2.asp<br />"
  3.  
  4. function function2()
  5.  function2 = "This is a function in File2.asp<br />"
  6. end function
  7. %>

Now when you open "File1.asp" in your browser, you should see
Code:
This is File1.asp
This is File2.asp
This is a function in File1.asp
This is a function in File2.asp

Looks right, yes? That does exactly what it looks like it does, right?

Now change line 3 of "File1.asp" to read
asp Code:
Original - asp Code