Caching in Classic ASP: Boosting Performance for Modern Times

ASP Tips: Tip 1: Cache Frequently-Used Data on the Web Server

While classic ASP may not be the shiny new framework, it's still powering plenty of sites. And let's face it, even the coolest tech needs a performance tune-up now and then.

That's where caching comes in. Forget slow database calls and sluggish page loads – let's leverage the web server's memory and disk for lightning-fast data access. In this updated take on the OG ASP tip, we'll dig into caching techniques and sprinkle in some practical code examples to get your pages humming.

Why Cache? You Won't Believe the Speed!

Remember the good ol' days of dial-up? Yeah, nobody wants their users back there reliving those painfully slow page loads. Caching takes a shortcut, storing frequently used data on the server, eliminating the need to re-fetch it from the database or disk with every request.

Think of it like keeping your pantry stocked with your favorite snacks. Instead of trekking to the store on every craving, you grab a quick bite in seconds. It's a win-win – faster response times for users and happier devs (and servers!).

What to Cache: Think Fresh, Think Frequently Used

Not everything deserves a VIP spot in your server's cache. Focus on data that:

  • Changes infrequently: Static content like combo box lists, reference tables, and configuration settings are prime candidates.

  • Has expensive retrieval: Data that takes ages to pull from the database (think extensive joins or complex queries) is perfect for caching.

  • Is heavily reused: Frequently accessed information like menu items or DHTML snippets become performance bottlenecks without caching.

A typical ASP page retrieves data from a back-end data store, then paints the results into Hypertext Markup Language (HTML). Regardless of the speed of your database, retrieving data from memory is a lot faster than retrieving data from a back-end data store. Reading data from a local hard disk is also usually faster than retrieving data from a database. Therefore, you can usually increase performance by caching data on the Web server, either in memory or on disk.

Caching is a classic space-for-time tradeoff. If you cache the right stuff, you can see impressive boosts in performance. For a cache to be effective, it must hold data that is reused frequently, and that data must be (moderately) expensive to recompute. A cache full of stale data is a waste of memory.

Data that does not change frequently makes good candidates for caching, because you don't have to worry about synchronizing the data with the database over time. Combo-box lists, reference tables, DHTML scraps, Extensible Markup Language (XML) strings, menu items, and site configuration variables (including data source names (DSNs), Internet Protocol (IP) addresses, and Web paths) are good candidates for caching. Note that you can cache the presentation of data rather than the data itself. If an ASP page changes infrequently and is expensive to cache (for example, your entire product catalog), consider pre-generating the HTML, rather than repainting it for every request.

Code Time: Let's Get This Party Cached!

There are two main ways to cache in classic ASP: using the Application object and the Response object.

Application Scope Caching:

This stores data for all users throughout the application's lifetime. Perfect for global settings or rarely updated content. But do not use this option to store database rows or records. Also do not try to use this for storing data for each users.

For example, we use Application level cache to store USD to INR exchange rate, which will refresh every 5 minutes. So, instead of calling an API or the database, we store the value in Application variable and use it on our code.

' Store data in Application object
Application("MyCachedData") = "This is my precious data!"

' Retrieve data later
If Request.QueryString("Refresh") = "Yes" Then
  ' Update data if requested
  Application("MyCachedData") = "Updated data!"
End If

' Use cached data
Response.Write Application("MyCachedData")

Response Scope Caching:

This stores data for the current user's session, ideal for personalized elements or recently viewed items. You might know this and have been using this for most of your application. But, again do not store huge data on Session variables.

For example, we use Session variable to store the user's email address, profile information, etc, which could be used to display on all the user logged in pages. If you can avoid storing too many data in Session variables, then it is really better.

' Cache data in Response object
Response.CacheControl = "Private"
Response.Expires = DateAdd("d", 1, Date) ' Expire in 1 day

' Store data in the session
Session("MySessionData") = "This is my user-specific data!"

' Retrieve data later
Response.Write Session("MySessionData")

File-Based Caching:

This is the type of caching we regularly use on almost all our applications.

We either store the data as

  • JSON

  • XML

  • HTML content itself (part of the page)

For example, we store the list of countries or list of currencies in JSON data in a file.
This would be refreshed when those respective tables are changed. Until then, those cache files would not be disturbed. We will then use this file to populate our drop down list instead of getting the data from database tables.

Function GetCachedData(cacheKey)
  Dim cacheFile
  cacheFile = Server.MapPath("cache/" & cacheKey & ".txt")

  If FileExists(cacheFile) Then
    Dim cachedData
    Set cachedData = CreateObject("Scripting.FileSystemObject").OpenTextFile(cacheFile).ReadAll
    GetCachedData = cachedData
  Else
    ' Generate data and cache it
    Dim dataToCache
    ' ... (retrieve or generate data)

    Set objStream = Server.CreateObject("ADODB.Stream")
    objStream.Open
    objStream.WriteText dataToCache
    objStream.SaveToFile cacheFile, 2 ' Overwrite existing file
    objStream.Close

    GetCachedData = dataToCache
  End If
End Function

Redis-Based Caching:

You have to use redis-com-client for this purpose. You can download it from here.

Set Redis = Server.CreateObject("RedisComClient")
' Pass in a configuration to connect to a server
Redis.Open("localhost")

' SetPermanent gives a key an indefinite TTL...
call Redis.SetPermanent("key1", "abcde")
Response.Write("Key1 = " & Redis.Get("key1") & "<br/>")

' ...but you can always change the TTL later
call Redis.Expire("key1", 60)
Response.Write("Key1 TTL = " & Redis.TTL("key1") & "<br/>")

' Or delete it alltogether
Redis.Del("key1")
Response.Write("Key1 is now gone... " & Redis("key1") & "<br/>")

' The key "stringkey" will have a TTL of 10 seconds
call Redis.Set("stringkey", "abcde", 10)

' We can also put keys and values in hashes...
call Redis.Hset("testhash", "firstfield", "firstvalue")
call Redis.Hset("testhash", "secondfield", "secondvalue")
Response.Write("Testhash[firstfield] = " & Redis.Hget("testhash", "firstfield") & "<br/>")
Response.Write("Testhash[secondfield] = " & Redis.Hget("testhash", "secondfield") & "<br/>")

' ...and expire the entire hash
call Redis.Expire("testhash", 60)
Response.Write("Testhash will expire in 60 seconds. The TTL is:" & Redis.TTL("testhash") & "<br/>")
dim result : result = Redis.Hget("testhash", "firstfield")
Response.Write("Here is our Testhash[firstfield] again:" & result & "<br/>")

' Or delete a complete hash in one go
Redis.Del("testhash")
Response.Write("Testhash is now gone...<br/>")
Set Redis = Nothing

Remember:

Caching is a balancing act. Don't overfill your server's memory or keep stale data hanging around. Implement expiration mechanisms and purge caches when necessary.

  • Implement cache invalidation mechanisms to ensure data freshness.

  • Choose caching techniques based on data size, access patterns, and performance requirements.

  • Consider security implications when storing sensitive data in caches.

  • Monitor cache performance and adjust as needed.

Beyond the Basics: Modernize Your Approach

While classic ASP has its limitations, don't despair! Consider these modernizing tips:

  • Out-of-process components: Offload database calls and complex processing to COM components for smoother server-side operations.

  • ASP.NET integration: Use ASP.NET features like output caching or data access layers for a more modern caching experience.

  • Performance monitoring: Keep an eye on your server resources and track caching effectiveness with tools like IIS logs or performance counters.

Caching is a powerful tool for squeezing every ounce of performance from your classic ASP applications. By understanding the principles and applying some code magic, you can keep your users happy and your servers humming, proving that even the classics can rock in the modern age.