REQUEST A DEMO

Setup ASP.Net caching using a super simple fluent interface

While reviewing what I did to Create an RSS Feed Using ASP.Net. We got worried that overzealous customers or feed readers might hit this feed kind of often, and since the data served up by the feed does not change too a lot we could easily do some caching. Luckily this is easy to do using ASP.Net’s built in caching support. Unfortunately the code to, programmatically, setup the caching is a little ugly. To make things easier to read I added a couple extension methods to create a very poor man’s DSL.

Following the Microsoft code example is ugly

 

Seeing the code below in my HttpHandler made me cringe. Hopefully it makes you cringe too.

 

TimeSpan freshness = Timespan.FromHours(1);
DateTime now = DateTime.Now;
context.Response.Cache.SetExpires(now.Add(freshness));
context.Response.Cache.SetMaxAge(freshness);
context.Response.Cache.SetCacheability(HttpCacheability.Server);
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.VaryByParams["days"] = true;

 

The essence of what I want to do is to have ASP.Net cache the content of the feed for a few minutes. It should also cache requests having the “days” parameter the handler accepts. I added that nifty “feature” without blogging about it. Please forgive me.

A Better Way

 

Let’s wrap the essence of what is being done into a couple of extension methods making the icky code above a bit easier to read and understand.

 

context.Response.CacheFor(30.Minutes()).OnParameters("days");

Fluenty Goodness

 

The, hopefully, easier to ready version of the cache setup code is accomplished with extension methods that use thefluent interface “compliant” Method Chaining technique.

 

public static class WebCachingExtension
{
    public static HttpResponse CacheFor(this HttpResponse response, TimeSpan timeSpan)
    {
        response.Cache.SetExpires(DateTime.Now.Add(timeSpan));
        response.Cache.SetMaxAge(timeSpan);
        response.Cache.SetCacheability(HttpCacheability.Server);
        response.Cache.SetValidUntilExpires(true);

        return response;
    }

    public static HttpResponse OnParameters(this HttpResponse response, params string[] parameters)
    {
        foreach (string parameter in parameters)
        {
            response.Cache.VaryByParams[parameter] = true;
        }

        return response;
    }

    public static TimeSpan Minutes(this int numberOfMinutes)
    {
        return TimeSpan.FromMinutes(numberOfMinutes);
    }
}

 

Ok, so there is also a little integer extension method in there to make a pretty TimeSpan. I use extensions like this all the time where they make sense and improve the readability of the code.

 

The key here is that the extension method returns the object being extended allowing the method calls to be chained together. The extended object in this case is the HttpResponse. The context being modified by the fluent interface in this case is the Cache object. Say you need some extra behavior? Just add another extension method. One downside to this trick is the lack of readability when you switch around the ordering of the calls.

 

context.Response.OnParameters(“days”).CacheFor(30.minutes())

 

Yuck. While, legal and correct it is at all easy to understand. I’ll punt on solving that problem in this blog post but I will say the solution lies in going to the next level and using an Expression Builder and potentially controlling the ordering of the method chain using interfaces.

 

Oops, I’ve said too much and slipped into more advanced waters that have been visited by smarter people that myself. I will bid you adieu.