4

I have one huge file.asp with all my reports. I have modularized the page using querystring, so this creates a lot of "virtual pages" with Report #1, Report #2, and so on.

I have some blocks of code I use more than once in the page. Actually I am repeating the code, but I already started to use Function to, for example format the date. But the block of codes are like panels with some selects in databases, tables, and so on... I mean, one panel can have more than 200 lines of code.

I would like to create some kind of function to reuse the code, instead of replicate it everytime. With classic asp, how many options I have? One that I have discarted is create one asp file per panel and in a master file include the panel where is necessary. I am really out of this approach. Is the Function the best approach?

4

I was the sole author of a very large class ASP application for almost a decade. There were several things I learned along the way that improved the quality of code and speed at which I could spit it out greatly.

First of all, instead of rewriting code over and over again, create a simple function that does the heavy lifting. It sounds like you're already doing this. This allows you to write the code faster with fewer mistakes, but also allows you to change the behavior or look-and-feel of the entire application by changing a few lines of code. It was my goal to place anything that was ever repeated in a function.

Secondly was when I realized that, yes, classic ASP does support classes. Instead of writing HTML and code for each of the many many reports, I created a report class that encapsulated the functionality I needed. Then all I had to do was pass a record set to the class and the report would be generated with a couple lines of code. If I was displaying a lot of tables and later wanted to make the rows sort-able by clicking on a column header, it was a trivial thing to roll this feature out to the entire application by modifying a single class.

Here are some things I turned into classes:

  • Tables that displayed record sets
  • Form to edit database records
  • Database queries (I never wrote SQL inline again)
  • Record sets so I could convert them into tables and other display types

The last thing I did that substantially improved the quality of the application was give up on ASP completely. I use to think "I don't really need a IDE", "Debugging with print statements is good enough". How wrong I was. Now that I've transitioned to C# and MVC I could never imagine going back to classic ASP.

|improve this answer|||||
  • Thanks for the reply. I will get into Classes and see the options. I am planning to shift to ASP.NET for sometime, but never actually started with a strong step. – Khrys Jul 10 '14 at 13:16
1

Classic ASP can be written totally modular using WSC (Windows Script Components) AKA scriptlets. These are files, written in VBscript or Jscript, that have properties and methods defined, and in that way they can be used just like COM components. The advantage is you don't have to register them or restart IIS after changing the code inside of them.

This is an example WSC (please note that this is untested, it is not fully functional and it might contain errors). Copy-paste this code in your ASP site somewhere and call it debugging.wsc:

<?xml version="1.0"?>
<component>
<?component error="true" debug="true"?>
<registration
    description="debugging"
    progid="debugging.WSC"
    version="1.00"
    classid="{AE434F7F-C64E-46D4-A103-FF3D47B05A91}"
>
</registration>


<public>

<!-- PROPERTIES -->
    <property name="executionTime">
        <get/>
    </property>

    <property name="logpath">
        <get/>
        <put/>
    </property>

<!-- METHODS / PUBLIC FUNCTIONS -->
    <method name="log">
        <PARAMETER name="inputValue"/>
    </method>

    <method name="send_mail">
        <PARAMETER name="who"/>
        <PARAMETER name="subject"/>
        <PARAMETER name="message"/>
    </method>

    <method name="hellofromjscript">
        <PARAMETER name="name"/>
    </method>

    <method name="getPersonByName">
        <PARAMETER name="name"/>
    </method>

    <method name="open"></method>

    <method name="close"></method>

</public>


<implements type="ASP" id="ASP"/>
<script language="VBScript">
<![CDATA[

' here is where global variables go
' every property has a corresponding global varibale
dim executionTime, logpath
dim fs, WriteFile

' start a timer every time this component is loaded
' this way we can debug the running time at various places in the ASP page
dim timeStart : timeStart = Timer()

'getters and setters for the properties'
function get_executionTime()
    get_executionTime = FormatNumber((Timer()-timeStart),4,,,0)
end function

function get_logpath()
    get_logpath = logpath
end function
function put_logpath(newValue)
    logpath = newValue
end function


'   *************************************************
'   *              PUBLIC FUNCTIONS                 *
'   *************************************************
function log(message)

    ' make sure the path you are logging to has 'modify' rights for the user of the current application pool in IIS

    ' determine path to the log file
    dim LOG_FILEPATH : LOG_FILEPATH = logpath & year(date)
    if month(date) < 10 then
        LOG_FILEPATH = LOG_FILEPATH & "0" & month(date) 
    else
        LOG_FILEPATH = LOG_FILEPATH & month(date) 
    end if
    LOG_FILEPATH = LOG_FILEPATH & filename & ".log"

    ' create the file if it doesn't exist
    If NOT fs.FileExists(LOG_FILEPATH) Then
        call    fs.OpenTextFile(LOG_FILEPATH, 2, True, 0)
        Set     WriteFile   = fs.OpenTextFile(LOG_FILEPATH, 2, True, 0)
                call WriteFile.WriteLine("Logfile Created " & currentDateTime)
                WriteFile.Close()
        Set     WriteFile   = Nothing
    End If

    ' write the log line
    Set WriteFile = fs.OpenTextFile(LOG_FILEPATH, 8, True, 0)
        call WriteFile.WriteLine(message)
        WriteFile.Close()
    Set WriteFile = Nothing

end function

function send_mail(who,subject,message)
' *******************************************************************'
' *                     E-MAIL A MESSAGE                            *'
' *******************************************************************'
' You need some variables in the application scope to use this method
' A WSC can access the standard ASP objects like server, request, application, session etc.
' because we included the <implements type="ASP" id="ASP"/> tag at the top.
    if hasValue(who) Then
        Dim myMail
        Set myMail      = CreateObject("CDO.Message")
            myMail.Subject  = subject
            myMail.From     = application.contents("DefaultEmailSender")
            myMail.To       = who & " <" & who & ">"
            myMail.TextBody = message
            myMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing")        = 2
            myMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver")       = Application.contents("MailServer")
            myMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport")   = 25 
            myMail.Configuration.Fields.Update
            myMail.Send
        set myMail      = nothing
    end if
End Function

function getPersonByName(name)
' It is also possible to return an object from a WSC
' just SET it in the return value and also SET it in the code that calls the function:
' Please note that this function not functional, just an example of what can be accomplished.
    sqlstatement =  "DECLARE " &_
                    "@username  varchar(50) " &_
                    "SELECT " &_
                    "@username = " & parameter.string(name) & " "
    ' parameter could be a WSC that parses user inputs and makes sure the application is protected
    ' against SQL injection attacks
    sqlstatement     = sqlstatement & "SELECT * "
    sqlstatement     = sqlstatement & "FROM Users "
    sqlstatement     = sqlstatement & "WHERE username = @username "
    ' DataAccessLayer could be another WSC that handles database connections and logs queries for example
    set getPersonByName  = DataAccessLayer.select(sqlstatement)
end function

' just an internal helper function.
' because it is not defined in the XML part at the top, this function can only be used internally
function hasValue(Val)
    hasValue = NOT(isNull(Val) OR Val="")
end function

'standard methods for opening and closing more objects - these can be extra WSC's as well'
function open()
    Set     fs = CreateObject("Scripting.FileSystemObject")
    logpath = Server.Mappath("/") & "\logs\\"
end function

function close()
    Set fs = Nothing
end function
]]>
</script>

<script language="javascript">
<![CDATA[

   function hellofromjscript(name){
   // Jscript works aswell. Keep in mind that Jscript is case-sensitive and 
   // that you will need to address the full ASP object, I.E. Application.Contents("myvar") instead of just Application("myvar")
        Response.Write("Hello " + name);
   };

]]>
</script>
</component>

A WSC can be used from ASP like this (provided you have the WSC in a directory called wscs):

<%
    dim debugging, recordset
    Set debugging = GetObject("script:"&Server.MapPath("/wscs/debugging.wsc"))
        debugging.open()

        debugging.log("Hello from a WSC")

        ' you can return objects like recordsets from a WSC:
        set recordset = getPersonByName("bill")
        set recordset = Nothing

        debugging.close()
    Set debugging = Nothing
%>

Using WSCs it is possible to load functionality conditionally (unlike include files, which are included always). It's possible to program using N-tier construnctions, as WSCs can load other WSCs.

You can find an example project that contains the use of WSCs and lots more helpful stuff on keeping an old ASP 3.0 application running on https://gitlab.com/erik4/classic-asp-book-examples

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.