Using OutputCache Action Filter in ASP.NET MVC 4.0

If you have used the output caching facility from the core ASP.NET platform, you are in familiar grounds. The OutputCache filter in ASP.NET MVC uses the same output caching facility and cache’s the output from an action method. Since the output is cached, subsequent request to the same URL are served using the same cache. Needless to say, this offers performance benefits especially for requests where database queries are involved.

In order to make output caching as easy as possible, the ASP.NET MVC Framework
provides OutputCacheAttribute which can simply be applied to any Controller action or even to the entire Controller class. By default, the content is cached with an absolute expiration time of 60 seconds. You can change this duration by modifying properties of the [OutputCache] attribute such as the Duration. However when memory resource become low, there is no guarantee that content will be cached for the amount of time that you specify.

Enough theory, let’s explore this filter with a working example


For this demonstration, I am using Visual Studio 2012 and Entity Framework. So let's get started by creating an ASP.NET MVC 4.0 application using Internet template as shown below –

createproj

Once your application is ready, let’s add a class called Product under Models folder and add some properties to this class –

public class Product
{
    public int ProductID { get; set; }
    public string ProductName { get; set; }
    public string Description { get; set; }
    public decimal UnitPrice { get; set; }
    public int AvailableQty { get; set; }
}


Once you have added the above details in our Product class, let’s add a Data Context which will help us to create a database with the table Products. Add a class in our Models folder with the name ShopingContext and write below code –

public class ShoppingContext : DbContext
{
    public ShoppingContext()
        : base("ShoppingConnectionString")
    {

    }
    public DbSet<Product> Products { get; set; }
}


The next step is to modify the DefaultConnection String as shown below in your Web.Config file –
<connectionStrings> 

<add name="ShoppingConnectionString" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=Shopping;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\Shopping.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>



Once the connection string is modified, now we will add a Controller with the name Product as shown below –

prodcontroller

Right click the Index and add a view as shown below –

addview

Keep the rest of the settings default. Now if you observe the Views folder, you will see a new folder with the name of controller. Product and Index.cshtml file got added to this folder.

Now let’s write some code in our Index action method which is available under Product Controller –

public class ProductController : Controller
{
    ShoppingContext dataContext = new ShoppingContext();
    public ActionResult Index()
    {
      ViewBag["ProductModifyTime"] = DateTime.Now;
        var query = from prod in dataContext.Products
                    select prod;
        return View(query);
    }
}



In the above code, we have created an object of ShoppingContext and we are querying the Products table using a LINQ Query under Index method. We are also passing the result of the Query to our view, so that we can display the data from the Products table in our Product’s Index view.

Run the application using the URL shown below –

productsurl

The very first time, you will not see any data. Because we are using Entity Framework Code First will create the database as per the connection string which we supplied in the constructor of our ShoppingContext class. You can find the database under SQL Server Object Explorer as shown below

database

Now let’s add some records in our Products table and then run the application. You will see the records displayed on our Index page as shown below –

productsoutput1

Modify the above view by removing the Links like Edit, Details, Delete and Create New. We will also display the Modified Date and Time of the products.

productsoutput2

To display the Products Modified Date and Time, add the following line in our Index.cshtml page for testing purposes –

<div><h4>Products Modified Date and Time - @ViewBag.ProductModifyTime</h4></div>

Now try refreshing the page and you will see the time gets changed with every refresh. With every request for the Index view, the action method Index under Product controller is getting executed and each time the database query also getting executed.

Assuming that there will be some situations where we will be adding/modifying/deleting the existing products, can we increase the performance of our page?

For increasing the performance of our page, we will make use of OutputCache Action filter. As I mentioned earlier, this attribute can be applied either on an individual action method or on the entire controller. Let’s apply this attribute on our Action Method Index which is available under Product Controller as shown below –

outputcache1

In the above OutputCache attribute, we are passing two parameters –
  • Duration – Duration is specified in Seconds.
  • VaryByParam – Vary caching using parameters like Query String.
Now let’s run the page and check the output by refreshing it multiple times. The page should be cached for 1 minute.

Now let’s test the VaryByParam attribute. Pass an ID parameter to the Index action methods and modify the code as shown below –

outputcache2

Now let’s pass ID as a query string to our URL and see the output of your page. When you pass the different IDs with the URL, the caching will vary based on the IDs. For example –

varyoutputcache

In the above image, we are passing ID=1 and ID=3 as a query string with our Product URL and the output is changed.

Now let’s decide the location of our cache. The cached output can be stored at various locations based on need and requirements. Let’s take a look at the following example –

cacheloc

There are several locations where you can cache the output. We are setting it to the Server where the request is processed. The default location value is “Any”.

There are several other options where you can vary the caching output. For example –
  • VaryByContentEncoding
  • VaryByCustom
  • VaryByHeader
You can also make use of SqlDependency to invalidate the cache when the cached data gets changed on the Server side.

Summary – In this article, we have seen how to use ASP.NET MVC OutputCache action filter to cache the output of the controller method and also vary the caching based on the requirement.





2 comments:

Oleg Kolpashchikov said...

VaryByCustom="browser" is an interesting option that should not be forgotten :)

Bill said...

While ASP.NET MVC has the attribute "OutputCache" which you mention, it doesn't always meet the expectations needed.

Like:
1) Control over the cache object.
2) Ability to add extra logic. Like enabling/disabling the cache or features of it on runtime.
3) Logic to manipulate the output before/after caching.
4) Some parts of it being dynamic and some static
5) Use the cache object/structure at other parts of the project as well.

I recently wrote a blog post on creating your own Custom Output Cache in ASP.NET MVC which meets the 5 criteria mentioned.

You can check it out here:
Custom Output Cache in ASP.NET MVC