Asp Classic Incluir una vez
-
03-07-2019 - |
Pregunta
¿ASP Classic tiene una función que sea equivalente a " de PHP; incluir una vez " característica?
Solución
Sé que este es un tema antiguo, pero pensé agregar mis dos centavos en caso de que alguien esté interesado.
Escribí una función que hace exactamente lo que quieres: incluye el archivo dado exactamente uno, sin importar cuántas veces se haya llamado.
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
Notas:
- Esto utiliza una función falsa simulada con una propiedad predeterminada. Si esto te molesta, se refactoriza fácilmente.
-
El diccionario debe ser persistente a través de todas las inclusiones, mientras que persistir en el fso simplemente evita reconstruirlo. Si no le gusta la idea de mantenerlos después de que se realicen las importaciones, puede modificar la clase para obtener una sintaxis como esta:
with new Importer .import "foo" .import "bar/baz" end with
Otros consejos
No. Lo siento. Tienes que gestionar te incluye a ti mismo.
Este fue uno de los problemas que encontré por primera vez después de heredar una aplicación ASP heredada. Mi solución actualmente es incluir todos los archivos genéricos de la biblioteca en un archivo llamado 'app-init.asp'. Este archivo se incluye en todas las páginas y le brinda un único punto de entrada para conectar la funcionalidad de la aplicación y una base sobre la cual construir.
Gracias Thom Smith por su código.
Debajo de una versión basada en la suya para manejar archivos fuente UTF8 (y quién administra abrir & amp; cerrar etiquetas ASP).
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
Como puede ver, no cierro la transmisión para permitir que se procesen más inclusiones.
Actualización: Dado que las rutas no distinguen entre mayúsculas y minúsculas, esta versión las convierte en minúsculas antes de agregarlas al Diccionario como claves. También se agregan antes de la evaluación del código, para evitar evaluaciones duplicadas en caso de bucle de inclusión (recursividad):
Dado A.asp y B.asp:
' A.asp
IncludeOnce Server.MapPath("/some/path/B.asp")
' B.asp
IncludeOnce Server.MapPath("/some/path/A.asp")
Dado que A
aún no se evalúa en absoluto en la inclusión de código B
, el segundo IncludeOnce
ocurrirá una evaluación duplicada si aún no está registrado en el diccionario, lo que no queremos. Esta actualización soluciona el problema.
Lo mejor que puede hacer es usar SSI para incluir archivos:
Como advertencia a la Respuesta usando ExecuteGlobal; Creo que ExecuteGlobal crea inestabilidad ya que VBScript no recolecta basura ni administra bien la memoria. Puede arrojar & Quot; Fallo catastrófico & Quot; o " ASP 0240 Script Engine Exception " errores porque está redefiniendo un objeto que no se eliminó correctamente.
Entonces, para usar esto, también necesitaría hacer sus inclusiones, las clases que tienen destructores y la inclusión deberían crear una instancia de la clase, persistir el nombre del objeto en el diccionario y el destructor ImportFunction debería destruir todos los objetos en el diccionario.
Las inclusiones no deben tener como prefijo las etiquetas ASP <%% > tampoco, mientras que usando un #include, necesitarías.
También debe tener en cuenta que ExecuteGlobal considera que todas las X = Y son asignación y no comparación, por lo que:
isMatch = (X = Y) 'puede producir resultados espurios.
El ejemplo incluye: -
Class aClass
Public Sub doSomething()
...
End Sub
End Class
Dim instance
Set instance = new aClass
He creado un ejemplo similar al anterior, pero usando el segundo estilo de pasar la inclusión a una Sub o asignación de propiedad
Lo que también hace es intentar recolectar basura destruyendo todos los objetos del diccionario, en su propio destructor. También elimina las etiquetas asp de las bibliotecas que envolvió.
<%
Class Libraries
private m_LoadedLibraries
private m_FileSystem
Private Property Get LoadedLibraries
If Not isInstantiated( m_LoadedLibraries ) Then
Set m_LoadedLibraries = Server.CreateObject("Scripting.Dictionary")
End If
Set LoadedLibraries = m_LoadedLibraries
End Property
Private Property Get FileSystem
If Not isInstantiated( m_FileSystem ) Then
Set m_FileSystem = Server.CreateObject("Scripting.FileSystemObject")
End If
Set FileSystem = m_FileSystem
End Property
Private Property Get IncludePath
IncludePath = "c:\include\"
End Property
Private Property Get LibrarySuffix
LibrarySuffix = ".inc.asp"
End Property
Private Sub Class_Terminate()
destroyObjects
Set m_LoadedLibraries = Nothing
Set m_FileSystem = Nothing
End Sub
Private Sub destroyObjects()
Dim objectName
For Each objectName in LoadedLibraries.Items
If Eval("IsObject(" & objectName & ")") Then
Execute "Set " & objectName & " = Nothing"
End If
Next
End Sub
Public Sub Include(ByVal libraryName, ByVal objectName)
libraryName = LCase( libraryName )
Dim library, filePath, script
If Not LoadedLibraries.Exists( libraryName ) Then
filePath = IncludePath + libraryName + LibrarySuffix
Set library = FileSystem.OpenTextFile( filePath )
script = library.ReadAll
script = stripAspTags( script )
ExecuteGlobal script
library.Close
LoadedLibraries.add libraryName, objectName
End If
End Sub
Private Function stripAspTags(ByVal script)
Dim buffer, location, startTag, stopTag, tagLength
startTag = Chr(60) + "%"
stopTag = "%" + Chr(62)
script = CStr( script )
tagLength = Len(startTag)
location = InStr(1, script, startTag, 1 )
If location > 0 Then
buffer = cleanString( Left( script, location + tagLength - 1 ) )
' Only strip off if it's the first part of the script
If Len( buffer ) = Len(startTag) Then
script = Mid( script, location + tagLength )
End If
End If
location = InStrRev(script, stopTag, -1, 1 )
If location > 0 Then
buffer = cleanString( Mid( script, location ) )
' Only strip off if it's the last part of the script
If Len( buffer ) = Len(stopTag) Then
script = Left( script, location - 1 )
End If
End If
stripAspTags = script
End Function
Private Function cleanString(ByVal target)
Dim objRegExp
Set objRegExp = New Regexp
objRegExp.IgnoreCase = True
objRegExp.Global = True
objRegExp.Pattern = "[\x00-\x1f]+"
cleanString = objRegExp.Replace( target, "")
Set objRegExp = Nothing
End Function
Private Function isInstantiated(ByVal target)
isInstantiated = ( IsNull( target) Or IsEmpty( target ) Or Not IsObject( target) )
End Function
End Class
Dim RequireOnce
Set RequireOnce = new Libraries
%>
Uso: -
With RequireOnce
.Include "aClass", "instance"
.Include "Database", "DataAccess"
.Include "Constants", "Constant"
.Include "LoginCheck", "Login"
End With