|
When I first started working with ASP.NET, one of the new features I was most
excited about was the built-in caching. Having worked on a few e-commerce
sites where much time was spent in optimizing for scalability, I had used
several "roll-your-own" techniques for caching. Typically this just meant
storing some dynamically generated HTML in a database table with a key of some
sort. Then I would schedule purges on some schedule and/or have methods
of deleting cached items on demand.
The built-in caching available with ASP.NET puts a fairly robust caching engine
at your disposal, but after working with it for awhile I confess there are
still some things lacking. The biggest one is that although you can cache
items based on dependencies, that dependency cannot be tied to an
action on a database in any kind of transparent way. (See the help for
more on the CacheDependency class, typically it would be an xml file, a
change to a directory, a change to another cached item, etc.)
There are hacks out there, such as using triggers to generate/delete a file of
some sort or maybe a Web service that monitors your database for changes
and changes some dependency file for you. I'm sure there are ways to
do it. Just nothing very clean and "built-in." I've heard through
the grapevine that database dependencies are high on the list of
added features in the next version.
I would like a dependency on a table row tied to a primary key or maybe on a
stored procedure resultset, if you want to get really fancy. For
instance, in any kind of online store scenerio, a piece of product usually has
at least one table row (and often other related rows) used to store product
information. Since this doesn't change often, it is an ideal candidate
for caching. However, when something changes, for instance a price,
available stock, color or whatever, you want that product page updated as close
to real-time as possible.
Here is another point to consider with page-level caching. I was
going to just make it easy on myself and cache the whole product page.
However, that page also has some search functionality in code-behind. And
you guessed it, if I cache the whole page, the search doesn't run because code
is not executed when the page is displayed from the cache. So back to the
drawing board on that one.
Luckily, it is relatively simple to just manage the caching yourself using
Cache.Add or Cache.Insert. I prefer the latter because Cache.Add throws
an exception if there is already an object in the cache with the name you are
trying to use. Plus you have more options with Cache.Insert. The
other good thing about adding items to the cache yourself is you can name them
a meaningful name, like something including a database primary key (ProductID)
for instance.
In traditional ASP, I already had templates written to display data a
certain way. My presentation classes pulled data from the database and
used the templates to format and return a string of HTML. I won't
argue the relative merits of using repeaters/datalists/datagrids now rather
than creating HTML from scratch. I do things both ways and probably will
change some of the code in the future. The thing is, you can cache HTML
if you want or a Dataset or a Hashtable or whatever works for your app.
Whenever you want to cache, just do something like this (watch wrapping):
Dim cacheName As String = "Product:" & ProductID.ToString
Dim content As String
If Cache(cacheName) Is Nothing Then
' assume presentation class returns a string of html
Dim oContent As New Presentation()
content = oContent.GetHtml_Product(ProductID)
oContent = Nothing
Cache.Insert(cacheName, content, Nothing,
Cache.NoAbsoluteExpiration, TimeSpan.FromHours(6))
' throw our content into a label
'(could also be a literal or whatever)
LblContent.Text = content
Else
LblContent.Text = Convert.ToString(Cache(cacheName))
End If
This code sample is really just a simple cache viewer allowing you to view and
delete these items from the cache as needed. Not terribly elegant, but
doesn't require a lot of dependency code. I'm not sure which is worse, to
output dependency files for every piece of product or manage it by hand.
Still too early in the learning curve to know for sure.
Of course if you are okay with the page being out of date for a few
hours, your time span should be the maximum length of time you are
comfortable with your page being out of date. Any caching should get
some additional scalability, all else being equal.
Keep in mind this page has to run in the same app space as your actual site, so
you might want to protect it with some authentication or something. There
are obviously much worse security threats than someone deleting cached items
from your site, but by the same token you really don't want anyone on this page
that shouldn't be.
The aspx page simply displays the current cache items in a datagrid.
When the page first renders, I don't show any of the cached content because it
can get rather long. Instead, there is a simple toggle linkbutton that
lets you see the actual cache contents if it is in a viewable form. This
works less well for datasets or items like that, but you could extend it.
For instance, use special notation when you name your cache items and then cast
them to the appropriate type when attempting to view them.
This is very elementary, but hopefully it will save somebody a little time or
give you some ideas. I'm still playing around with some dependency ideas
as well, but this might do for now.
Added 5/6/2002
|