Asp Classic Include Once
I know this is an old topic, but I thought I'd add my two cents in case anyone's interested.
I wrote a function that does precisely what you want: includes the given file exactly one no matter how many times it was called.
class ImportFunction
private libraries_
private fso_
private sub CLASS_INITIALIZE
set libraries_ = Server.createObject("Scripting.Dictionary")
set fso_ = Server.createObject("Scripting.FileSystemObject")
end sub
public default property get func (path)
if not libraries_.exists(path) then
on error resume next
with fso_.openTextFile(path)
executeGlobal .readAll
if Err.number <> 0 then
Response.write "Error importing library "
Response.write path & "<br>"
Response.write Err.source & ": " & Err.description
end if
end with
on error goto 0
libraries_.add path, null
end if
end property
end class
dim import: set import = new ImportFunction
Notes:
- This uses a faux function simulated with a default property. If this bothers you, it's easily refactored.
The dictionary must be persistent through all includes, whereas persisting the fso merely avoids reconstructing it. If you don't like the idea of keeping them around after the imports are done, you could modify the class to get syntax like this:
with new Importer .import "foo" .import "bar/baz" end with
No. Sorry. You have to manage includes yourself.
Thanks Thom Smith for your piece of code.
Below a version based on yours to handle UTF8 source files (and who manages opening & closing ASP tags).
Dim IncludeOnce
Class IncludeOnceClass
Private libraries_
Private adostream_
Private Sub CLASS_INITIALIZE
Set libraries_ = Server.createObject("Scripting.Dictionary")
Set adostream_ = CreateObject("ADODB.Stream")
adostream_.CharSet = "utf-8"
adostream_.Open
End Sub
Public Default Property Get includeFile (path)
Dim lpath : lpath=LCase(path)
if Not libraries_.exists(lpath) then
Dim code
libraries_.add LCase(lpath), "stuff"
On Error Resume Next
adostream_.LoadFromFile(lpath)
code = Replace(Replace(adostream_.ReadText(),"<"&"%",""),"%"&">","")
executeGlobal code
If Err.number <> 0 Then
Response.write "Error importing library "
Response.write lpath & "<br>"
Response.write Err.source & ": " & Err.description
Response.write "<pre><tt>" & replace(code,"<","<") & "</tt></pre>"
Response.End
End if
On Error Goto 0
End If
End Property
End Class
Set IncludeOnce = new IncludeOnceClass
As you see, I don't close the stream to let further includes be processed.
Update: Since paths are case insensitive, this version converts them to lower case before adding to the Dictionary as keys. Also they are added before code evaluation, to prevents duplicate evaluations in case of inclusion loop (recursion) :
Given A.asp and B.asp :
' A.asp
IncludeOnce Server.MapPath("/some/path/B.asp")
' B.asp
IncludeOnce Server.MapPath("/some/path/A.asp")
Since A
is not yet evaluated at all at B
code inclusion, the second IncludeOnce
will occur a duplicate evaluation if it's not yet registered in the dictionary, which we won't want. This update fixes the issue.