ASP.NET MVC Action Filter - Caching and Compression

Caching plays a major role in developing highly scalable web applications. We can cache any http get request in the user browser for a predefined time, if the user request the same URL in that predefined time the response will be loaded from the browser cache instead of the server. You can archive the same in ASP.NET MVC application with the following action filter:

using System;
using System.Web;
using System.Web.Mvc;

public class CacheFilterAttribute : ActionFilterAttribute
    /// <summary>
    /// Gets or sets the cache duration in seconds. The default is 10 seconds.
    /// </summary>
    /// <value>The cache duration in seconds.</value>
    public int Duration

    public CacheFilterAttribute()
        Duration = 10;

    public override void OnActionExecuted(FilterExecutedContext filterContext)
        if (Duration <= 0) return;

        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);

        cache.AppendCacheExtension("must-revalidate, proxy-revalidate");

You can apply the filter in your Controller action method like the following.

[CacheFilter(Duration = 60)]
public void Category(string name, int? page)

The following shows the screen-shot in firebug  when cache filter is not applied:

and this is the screen-shot when the cache filter is applied:

Another important thing is compression. Now a days, all modern browsers accept compressed contents and it saves huge bandwidth. You can apply the following action filter to compress your response in your  ASP.NET MVC application:

using System.Web;
using System.Web.Mvc;

public class CompressFilter : ActionFilterAttribute
    public override void OnActionExecuting(FilterExecutingContext filterContext)
        HttpRequestBase request = filterContext.HttpContext.Request;

        string acceptEncoding = request.Headers["Accept-Encoding"];

        if (string.IsNullOrEmpty(acceptEncoding)) return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("GZIP"))
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        else if (acceptEncoding.Contains("DEFLATE"))
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);

Just decorate your controller action with this filter:

public void Category(string name, int? page)

The following shows when compression is not applied:

and this is the screen-shot when the compress filter is applied:

You can also apply both these filter in the same action method, like the following:

[CompressFilter(Order = 1)]
[CacheFilter(Duration = 60, Order = 2)]
public void Category(string name, int? page)

And this is the screen-shot:



kick it on


  • Thanks a bunch for posting these. Your whole MVC series has been great

  • Simple and clear, and easy to follow!
    Thank you Kazi

  • Nice, I like the compression filter, but the "Browser Cache" filter doesn't seem to do anything.

    my Cache-Control header is "private, must-revalidate, proxy-revalidate, max-age=60" even tho we're obviously trying to set it to "public ...". I don't understand that.

    Maybe that is affecting it but no matter how many times i request my page the Request Headers don't contain a Modified-Since entry.

    With browser cache, the browser should send the request asking if the file has been modified since the date of the cached version. But in the case of dynamic pages the server should always say the file has just been modified so would send the page down every time anyway.

    We'd have to send down a false modified date to get the browser to use its cached version.

  • @Everyone: Thanks.

    @tgmdbm: I think I need to clarify more on Browser caching. Content can be cached by both Cach-Control header(The CacheFilter in this case) and ETag(Which I guess you are mentioning). The advantage of Cache-Control over ETag is, the browser does not send a request to server to check if the content has been modified in that cache priod, but for ETag the browser sends a request to Server to check if the content is modified and if the content is not modified the server sends a 304(Not Modified). So using Cache-Control you are reducing the extra Roundtrip of the server. Also ETag is more appropriate for static files like image, css, js where the web server aumatically genarates the values of ETag.

    The following is an excellent article on Http Cache:

  • Very very nice!

    Keep up the good work!

  • Hey What utility are you using in the screenies???

  • Very useful code. Thanks for introducing these.

    One suggestion about compression, it's always better to use IIS 6.0's built in compression over any ASP.NET code, whether a filter or an HttpModule when it comes to scalability. IIS Native compressor always performs better than the .NET components. Moreover, you can increase/decrease compression ratio and balance speed over size.

    See here how to turn on IIS compression on dynamic ASP.NET requests:

    However, in IIS, you specify which extensions to compress. Now that MVC is almost extensionless, this introduces an interesting challenge - how will IIS know which extension to compress?

  • @azamsharp: Thanks. Sure I will.

    @Mad Dog: Print Screen + MS Paint.

    @Omar: Thanks for comments, Yes, I agree IIS Compression is always better but most of the shared hosting does not allow to modify the IIS metabase. For those who are running dedicated IIS6 can surly turn on the compression like you mentoned in your blog.

  • Is it possible to do this on the controller level. Say I want to compress all the actions of the controller. Is there any other way to apply this attribute to every action of the controller?

  • @yang :
    Sure, just apply it in your controller instead of the action methods.

  • I have xml file I loaded into cache
    is there any way I can see the cache content and modify it
    if you have some example please send


  • You should update the sample to change the FilterExecutedContext (ActionExecutedContext) and FilterExecutingContext (ActionExecutingContext) to reflect the changes in preview 3.

    I also made a minor change to the caching filter to set the cacheability to HttpCacheability.NoCache when the duration is <= 0. Not sure if that was necessary but I wanted to make sure that a few actions were not cached.

    Other than that, thanks for the great post!

  • Excellent on the compression part!

    I updated for Preview 4 - one minor change:

    public override void OnActionExecuting(ActionExecutingContext filterContext)

    Now accepts a 'ActionExecutingContext'

    Thanks again!

  • Great article!

    Any idea of the reason that one should implement the action filter you suggest for caching output instead of using a cache profile on the web.config file and call the [OutputCache(CacheProfile = "myCahceProfile")] on the action?
    This way, any changes to the caching profile (duration for example) can be implemented in the web.config file without even recompiling the application.


  • nice, really nice!

Comments have been disabled for this content.