TheDeveloperBlog.com

Home | Contact Us

ASP.NET Cache Expiration

This C# article examines caching and expiration in ASP.NET. It considers best practices.

Expiration is key to caching in ASP.NET. We need a balance between memory usage and performance.

Large caches can reduce performance, resulting in pages being expired much sooner. And small caches simply do not cache enough data.

Cache

Intro. Let us begin our exploration of expiration times. ASP.NET applications are continually recycled. ASP.NET on IIS 7.0 uses a special process model, which greatly enhances the reliability of the programs you are running.

And: IIS 7.0 feels resources are scarce. It will unload your web site at any time it feels like it.

Cache size. You may use a singleton or static class to store a lot of data. This can enhance performance, but it can also lead the server to restart your application more often, thus increasing the amount of work.

Large cache: ASP.NET will decide your process is using too much memory. Process will be restarted. This will invalidate all your caches.

Medium or small cache: Your process will use less memory. ASP.NET will let it keep going longer.

Balance. You want a balance between too much caching and too little caching. Here I am dealing with a mostly static site, which can be built from database queries or just plain aspx pages.

And: Popular pages such as the home page should be kept in the cache longer, even indefinitely.

Tip: Don't double-cache. There are patterns where data were kept in two different caches. This is hugely inefficient.

Example. Here is an example and explanation of sliding caching. I feel that this is the best solution for this type of site. The following code is a static class, which means it doesn't need to save state.

Tip: You can add it to App_Code and call it from anywhere. You will need to include some namespaces.

Static cache helper method: C#

public static class CacheHelper
{
    const int _seconds = 600;
    public static void CacheThis(HttpResponse response)
    {
	// Only cache for X seconds.
	response.Cache.SetExpires(DateTime.Now.AddSeconds(_seconds));
	response.Cache.SetMaxAge(new TimeSpan(0, 0, _seconds));
	response.Cache.SetCacheability(HttpCacheability.Public);
	response.Cache.SetValidUntilExpires(true);

	// Sliding expiration means we reset the X seconds after each request.
	// SetETag is required to work around one aspect of sliding expiration.
	response.Cache.SetSlidingExpiration(true);
	response.Cache.SetETagFromFileDependencies();
    }
}

Page that calls cache class: C#

protected void Page_Load(object sender, EventArgs e)
{
    CacheHelper.CacheThis(Response);
}

The method uses SetSlidingExpiration and a small workaround. I decided that 10 minutes is a good minimum amount of time to cache. ASP.NET will restart often on a shared server, so anything longer might make things worse.

The code example uses the output cache. The first four lines of code set the output cache for the page as usual. This is done programmatically (with code) instead of declaratively (with markup).

Finally: The expiration time is reset. What sliding expiration does is reset the expiration time after each access.

Expiring. We assume a cache time of 10 minutes. If someone visits at 0 seconds, the page will be generated. Then if someone else visits after 9 minutes have passed, it will be served from the cache, and the expiration time will be reset.

Then: The page will expire from the output cache after 19 minutes. This is a good behavior.

Summary. We saw that there is an intricate cache behavior of ASP.NET on a shared host like many sites use. Memory pressure, and recycling all play a part and putting too many things in the cache will hurt performance.

And: This happens primarily because ASP.NET will restart the process more often.