Archive | June 2012

Custom Output Caching with MVC3 and .NET 4.0 – Done Properly!

I came across a need at work today to re-implement some of the Output Caching for our MVC3 application which runs under .NET 4.0. I wanted to use standard Output Caching (via the OutputCacheAttribute class, why re-invent the well-working wheel?) but due to some of our requirements I needed more control over how my objects were cached. More specifically, I needed to cache them with a custom Cache Dependency. With a little bit of Google-Fu, I was delighted to learn of the Output Cache Provider functionality introduced in ASP.NET 4. I implemented a custom OutputCacheProvider, registered it in my Web.config file as the Default Cache Provider, and I was well on my way.

…Or so I thought. You see, in our application we are caching both regular (Parent) and partial (Child) Controller Action Method calls. That is to say, we’re caching regular calls to Controller Action Methods, as well as the outputs of Child Action Method calls which are invoked from uncached Parent Action Method calls. While testing, some strange behaviour showed me that my Child Action Method calls were not being cached by my shiny new custom Output Cache Provider. They were instead being cached by the Default Output Cache Provider, which I have no control over. I confirmed this by debugging and seeing that my Child Action Method calls were not hitting my Custom Output Cache Provider methods… What gives?

I did some more Googling and learned very little, but happened to come across this little tidbit of somewhat vague information. I also came across a few .NET bloggers that had solved this problem… how shall I say… VERY poorly. So, I’d like to tell you how to do it correctly.

In the .NET 4.0 edition of the MVC3 assemblies, the OutputCacheAttribute contains a static property called ChildActionCache which is of type ObjectCache. As you can see from the MSDN page (at least at the time of writing this), they aren’t exactly detailing what it is for or how it really works – or why you can’t just use the bloody OutputCacheAttribute for Child Action Method calls. So what is going on?

Well, after a little investigation, I discovered the reasoning behind the madness. Basically, from a high level view, the OutputCacheAttribute works in conjunction with a Caching Http Module (the OutputCacheModule class). Each HTTP Request is passed to the OutputCacheModule LONG before it reaches your MVC application (FYI, this is called kernel-level IIS caching), and if the Http Module can pull a cached Response for that particular Request out of the Cache, it will short circuit your application and simply render the response to the user, stopping further execution. When this happens, your application never even sees the request. Neat, huh? If it can’t find the request, it exits and lets your application do its thing… And whenever you’ve placed OutputCache on your Action Method, it will cache the response in the same format that the Http Module looks for. This allows for MUCH less work to be done by your application in caching things. Cool, right?

You may now see why you cannot cache Child Action Method calls using the regular old OutputCacheAttribute… Your MVC application needs to execute a Parent Action Method from which the Child Action Methods are executed. If your Child Action Method was cached in the same way as a Parent Action Method, the HttpModule would always perform a Cache-miss since the Child Request originates from the Parent and has a completely different method signature, parameters, etc. upon which the Cache Key is derived. How can you cache your Child Action Methods ahead of your MVC application when your MVC application needs to execute in order to generate the Child Action Method Requests? And so, OutputCacheAttribute only works in the traditional manner for Parent Action Method calls.

So, how do you “fix” this and handle the Caching of Custom Child Action Methods in the same way as Parent Action Methods? First, create a custom class that inherits from the MemoryCache object. In this class you’re going to override 2 methods:

/// <summary>
/// A Custom MemoryCache Class.
/// </summary>
public class CustomMemoryCache : MemoryCache
{
    public CustomMemoryCache(string name)
        : base(name)
    {

    }
    public override bool Add(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
    {
        // Do your custom caching here, in my example I'll use standard Http Caching
        HttpContext.Current.Cache.Add(key, value, null, absoluteExpiration.DateTime, 
            System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);

        return true;
    }

    public override object Get(string key, string regionName = null)
    {
        // Do your custom caching here, in my example I'll use standard Http Caching
        return HttpContext.Current.Cache.Get(key);
    }
}

You’re going to build your custom Output Cache Provider (mentioned at the beginning of this post) similarly, inheriting from the abstract class OutputCacheProvider. Here’s an example one:

/// <summary>
/// A Custom OutputCacheProvider Class.
/// </summary>
public class CustomOutputCacheProvider : OutputCacheProvider
{
    public override object Add(string key, object entry, DateTime utcExpiry)
    {
        // Do the same custom caching as you did in your 
        // CustomMemoryCache object
        var result = HttpContext.Current.Cache.Get(key);

        if (result != null)
        {
            return result;
        }

        HttpContext.Current.Cache.Add(key, entry, null, utcExpiry,
            System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);

        return entry;
    }

    public override object Get(string key)
    {
        return HttpContext.Current.Cache.Get(key);
    }

    public override void Remove(string key)
    {
        HttpContext.Current.Cache.Remove(key);
    }

    public override void Set(string key, object entry, DateTime utcExpiry)
    {
        HttpContext.Current.Cache.Add(key, entry, null, utcExpiry,
            System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
    }
}

You’ll notice that Add and Set are similar, but that Add checks for and returns the object from Cache if it exists, before attempting any Caching. This is the expected behaviour of the Add method according to MSDN and thus you should code it as above.

Now your Web.config needs a few simple lines added in order to be configured to use your CustomOutputCacheProvider:

<system.web>
  <caching>
    <outputCache defaultProvider="CustomProvider">
      <providers>
        <clear/>
        <add name="CustomProvider" type="MyMvcApp.Caching.CustomOutputCacheProvider, MyMvcApp"/>
      </providers>
    </outputCache>
  </caching>
</system.web>

The defaultProvider segment above allows you to set the Named Output Cache Provider that should be used by default for all Output Caching.

With the classes and configuration in place, you’ve now configured all Parent Action Methods which are decorated with [OutputCache] to use your new Custom Output Cache Provider! But we still need to configure Child Action Methods to do the same Caching as Parent Action Methods. This is where your custom MemoryCache object comes into play. Modify your Global.asax to wire your CustomMemoryCache into the OutputCacheAttribute:

protected void Application_Start()
{
    // Register Custom Memory Cache for Child Action Method Caching
    OutputCacheAttribute.ChildActionCache = new CustomMemoryCache("My Cache");
}

As an FYI, for your CustomMemoryCache object, and MemoryCache objects in general, here’s some information how to configure them by Name using your Web.config or App.config – very useful. You’ll note that I named my MemoryCache “My Cache” above – the name isn’t optional, but it has no effect unless it matches a Named Cache entry in your Web.config or App.config file; if it does match, it will adhere to the rules of your Named Cache. If, on the other hand, your MemoryCache object doesn’t use Runtime Caching and instead writes to a database or other external source such as AppFabric, the Named Cache will have no effect since it applies only to in-process Runtime Caching.

And that’s it! You’ve got a fully custom Output Caching solution in .NET 4.0 for your MVC3 application that correctly leverages standard Microsoft hooks and components! Thanks for reading this long post – comments and criticisms welcomed as always.

LINQ and Deferred Execution

As of .NET 3.0, LINQ (and the often related Lambda Expressions) have been available for our use and abuse. LINQ stands for Language INtegrated Query, and is a method of modelling OO data in a more or less relational sense that is not unlike databases. And just like databases, it comes with a cost.

To offset this cost, LINQ uses Deferred Execution. Deferred Execution means that the code is not executed until it is needed. This means that the LINQ code that you write is not actually executed until you NEED to execute it – typically during an enumeration of the results.

An example. Let’s create an array of 1,000,000 integers, all of random values between 1 and 10000, and sort them in an ascending fashion using LINQ:

static void Main(string[] args)
{
    // Anytime that you know the size of your list, specify 
    // it in the constructor. This enables much more efficient 
    // processor and memory usage
    var myIntegers = new List<int>(1000000);

    // Initialize RNG
    var random = new Random();

    // Populate the list with random numbers
    for (int i = 0; i < 1000000; i++)
    {
        myIntegers.Add(random.Next(1, 10000));
    }

    var stopwatch = new Stopwatch();
    stopwatch.Start();

    // LINQ time, let's sort them
    var result = myIntegers.OrderBy(i => i);

    stopwatch.Stop();
    Console.WriteLine("LINQ OrderBy Time: " + stopwatch.ElapsedMilliseconds + " ms");

    Console.ReadKey();
}

And the output:

LINQ Order By Result

LINQ Order By Result

Note how little time it took to Order the results – only 0 ms! Seems a bit fishy that we sorted 1,000,000 integers in less than 1 millisecond, doesn’t it? This is because our application didn’t actually sort them at all. Via the power of Deferred Execution, your .NET application is intelligent enough to know not to actually execute any LINQ queries until you NEED to. Note that since we never did anything with the result, the sort never actually happened.

What did happen, however, was the creation of a .NET object called an Expression Tree. An Expression Tree is used for “meta programming” – basically writing code that writes code. LINQ automatically generates an Expression Tree for your query – which it can build upon as you tag on additional queries – that isn’t executed until it needs to be executed. This allows you to do all of the neat things that LINQ supports like joins, selecting based on a particular class property or value, and so on. The generation of this Expression Tree is actually all that has happened so far in our application, and it took approximately 0 ms – cheap!

Recall now that LINQ can be performed on 2 types of objects: IEnumerable<T> and IQueryable<T>. Since IEnumerable<T> exposes only one method, GetEnumerator, it is safe to say that LINQ queries against IEnumerable<T> objects are only actually executed whenever enumeration actually occurs. To prove this, let’s alter the code slightly by adding a ToList() call to our OrderBy() call – ToList() forces an enumeration of the collection to gather results, so our OrderBy will actually do the work of ordering things:

static void Main(string[] args)
{
    // Anytime that you know the size of your list, specify 
    // it in the constructor. This enables much more efficient 
    // processor and memory usage
    var myIntegers = new List<int>(1000000);

    // Initialize RNG
    var random = new Random();

    // Populate the list with random numbers
    for (int i = 0; i < 1000000; i++)
    {
        myIntegers.Add(random.Next(1, 10000));
    }

    var stopwatch = new Stopwatch();
    stopwatch.Start();

    // LINQ time, let's sort them
    // This time we force the enumeration with ToList()
    var result = myIntegers.OrderBy(i => i).ToList();

    stopwatch.Stop();
    Console.WriteLine("LINQ OrderBy Time: " + stopwatch.ElapsedMilliseconds + " ms");

    Console.ReadKey();
}

And the result:

LINQ Order By Then Any Result

LINQ Order By Then Any Result

A whopping 356 ms – seems a little more realistic for performing a sort than 0 ms!

Why is LINQ done this way? Why not execute each query immediately as the LINQ method is called? The answer is efficiency. I’d love to get further into the nitty gritty details of why, but Charlie Calvert explains it better than I probably would. I will, however, cover Expression Trees in a future post – they’re a ton of fun. 🙂