ASP Classic: Simulating ASPCache

by Jon Davis 13. December 2008 06:36

This is for you folks who, like me, have found themselves having to deal with legacy ASP Classic code.

At my workplace, there are mountains of ASP files that make use of a component called ASPCache which when Googled looks like it comes from here:

This component appears in the global.asa like so:

<object runat="server" scope="application" id="Cache"
  progid="ASPCache" viewastext></object>	

Then, references to Cache appear throughout the code:

bAdded=Cache.Add(CacheKey, value, 60000) ' Cache for 1 minute	

.. and ..


The code runs on two servers: a production server and a dev server. But for mainenance and new projects, I prefer to work locally. Since I did not have the ASPCache component, the entire site was crippled by the presence of this ASPCache dependency when I attempted to execute the web app from within my local instance of Windows XP + IIS 5.

Ignoring The Cache

The legacy code was already written in such a way that if ASPCache failed to take or to return a value it would work around it; the problem is that it didn't know how to live without the presence of the ASPCache dependency.

So the first thing I did to work around the problem was to just cripple the ASPCache dependency in global.asa.

REM #### obXXject runat="server" scope="application" id="Cache"
  progid="ASPCache" viewastext /obXXject	

.. and then wrap ASPCache invocations with error-ignoring handlers ..

On Error Resume Next ' no cache
    bAdded=Cache.Add(CacheKey, value, 60000) ' Cache for 1 minute
On Error Goto 0


On Error Resume Next
On Error Goto 0

This worked fine for me locally; at this point I was able to execute my code.

But there were several files I had to apply this to, and the next problem is that there are about twenty different web sites with much of this same duplicate source code.

Worse--much worse--I had essentially killed off the ASPCache dependency from global.asa. I could never check in / commit this file back to Subversion without breaking the production codebase, unless I reversed these changes. It was frankly too easy to accidentally commit the entire site with all my changes including global.asa's removal of the dependency, and I didn't want this to happen.

So what I've decided to do was to reproduce the ASPCache API with my own COM object using the above-described interfaces.

Creating My Own ASPCache

To reproduce ASPCache, the requirements per the above samples are really quite simple:

  1. The <object> tag tells me that it needs a ProgID of "ASPCache". ProgIDs are to COM what DNS host names are to the Internet; they are mappings to CLSIDs (class IDs), which are GUIDs, like DNS host names map to IP addresses. The CLSIDs are registry keys that map back to a COM DLL, such as ASPCache's DLL.
  2. The COM interface needs to have a default function or property that returns an item when being supplied a key. Default properties / functions are an exclusive feature of VB6--they are not available in VB.NET, VBScript, or most other languages, but the behavior is not unlike an indexer in .NET that wraps a particular hashtable or function.
  3. The COM interface also needs an "Add" function that takes a key, the value to be cached, and a value indicating, in milliseconds, how long the item should remain in the cache.

This blog entry took me about 10x more time to document than it took me to create the ASPCache equivalent detailed herein; I love blogging. ;)

To produce this component, I fired up Visual Basic 6. Visual Basic 6 is still available for download on MSDN as far as I know, as it's still the only way to easily produce first-class COM objects without resorting to .NET CCW's, C++, or Delphi. I spent a few years in my past, back in the 90's and very early 2000's, working with VB 5/6 to create COM objects and Windows applications, so this was not foreign territory for me. At this point I'll walk through the steps as a tutorial.

  1. In the Visual Basic 6 New Project dialog, choose "ActiveX DLL".
  2. The project that gets created is called "Project1", with a single item in the project called "Class1". Rename "Class1" to "ASPCache" using the Properties tool window on the right side of the screen.
  3. The project needs to be renamed as well. I changed it to "VirtualASPCache".

  4. In the class formerly named "Class1" (now "ASPCache"), I used the following code:

    Dim cacheCol As New Collection
    Dim cacheTmr As New Collection
    Dim m_flushenabled As Boolean
    Dim m_flushtimeout As Long
    Dim m_flushinterval As Long
    Public Property Get Item(key) As Variant
        Dim tmr
        On Error Resume Next
            tmr = cacheTmr(key)
        On Error GoTo 0
        If Not IsEmpty(tmr) And Not IsNull(tmr) Then
            If tmr < Now Then
                cacheTmr.Remove key
                cacheCol.Remove key
            End If
        End If
        On Error Resume Next
        Item = cacheCol.Item(key)
    End Property
    Public Property Let Item(key, ByVal vNewValue As Variant)
        cacheCol(key) = vNewValue
    End Property
    Public Function Add(key, value, Optional time_period As Long = 0) As Boolean
        Dim tmr
        If time_period = 0 Then time_period = 60000 * 60 * 30 ' 30 minutes
        tmr = DateAdd("s", (time_period / 1000), Now)
        On Error Resume Next
            cacheCol.Add value, key
            If Err.Number <> 0 Then
                On Error GoTo 0
                Add = False
                cacheCol.Remove key
                cacheCol.Add value, key
                On Error Resume Next
                    cacheTmr.Remove key
                On Error GoTo 0
                cacheTmr.Add tmr, key
                Exit Function
            End If
        On Error GoTo 0
        cacheTmr.Add tmr, key
        Add = True
    End Function
    ' ignored
    Public Property Get FlushEnabled() As Boolean
        FlushEnabled = m_flushenabled
    End Property
    ' ignored
    Public Property Let FlushEnabled(ByVal enabled As Boolean)
        m_flushenabled = enabled
    End Property
    ' ignored
    Public Property Get FlushTimeout() As Long
        FlushTimeout = m_flushtimeout
    End Property
    ' ignored
    Public Property Let FlushTimeout(ByVal Timeout As Long)
        m_flushtimeout = Timeout
    End Property
    ' ignored
    Public Property Get FlushInterval() As Long
        FlushInterval = m_flushinterval
    End Property
    ' ignored
    Public Property Let FlushInterval(ByVal Timeout As Long)
        m_flushinterval = Timeout
    End Property
  5. Make the Item property the default property. To do this, hit F2 to open up the Object Browser. Then at the top left drop-down menu, filter by your project. Select ASPCache, then on the right find Item. Right-click on it, choose Properties, and then expand the Advanced view. On the left is a Procedure ID drop-down where you can specify "Default".
  6. Save the project (File -> Save Project)
  7. Make the DLL (File -> Make VirtualASPCache.dll)
  8. In a command prompt (Windows Start menu -> Run... -> cmd.exe) navigate to your project ("cd \myprojects\virtualaspcache", etc) and register the DLL to the COM registry:
    regsvr32 VirtualASPCache.dll
  9. Almost there. Now we need to change the ProgId. VB6 uses the following convention for ProgID: "{ProjectName}.{ClassName}". So for us that would be "VirtualASPCache.ASPCache". So, pull up Registry Editor (Windows Start menu -> Run... -> regedit.exe). Under HKEY_CLASSES_ROOT, find a key (keys look like directories on the left; values are on the right) called "VirtualASPCache.ASPCache".

    Rename "VirtualASPCache.ASPCache" to "ASPCache".  

Restoring the original code in global.asa, not only am I able to retain the dependency reference, the cache API actually works, it is not merely walked over. So now I can retain all the original ASP code as-is, and it should all function pretty much the same.

Download: (8.31 kb)

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Web Development


Powered by BlogEngine.NET
Theme by Mads Kristensen

About the author

Jon Davis (aka "stimpy77") has been a programmer, developer, and consultant for web and Windows software solutions professionally since 1997, with experience ranging from OS and hardware support to DHTML programming to IIS/ASP web apps to Java network programming to Visual Basic applications to C# desktop apps.
Software in all forms is also his sole hobby, whether playing PC games or tinkering with programming them. "I was playing Defender on the Commodore 64," he reminisces, "when I decided at the age of 12 or so that I want to be a computer programmer when I grow up."

Jon was previously employed as a senior .NET developer at a very well-known Internet services company whom you're more likely than not to have directly done business with. However, this blog and all of have no affiliation with, and are not representative of, his former employer in any way.

Contact Me 

Tag cloud


<<  May 2021  >>

View posts in large calendar