MVC and the HTML5 Application Cache

HTML5 has loads of awesome features and recently I have been playing around with a feature called the Application Cache. The Application Cache is designed to allow you to run your web application offline - that is, without a network connection. A web browser that implements HTML5 offline applications will read the list of URLs from the manifest file, download the resources, cache them locally, and automatically keep the local copies up to date as they change. When you don't have a network connection, the browser will automatically switch over to the local copies instead. Most modern browsers offer support for the Application Cache this includes FIREFOX (3.5+), SAFARI (4.0+), CHROME (5.0+), OPERA (10.6+), IPHONE and ANDROID. Unfortunately, Internet Explorer doesn't currently offer support for Application Cache.

So...what if we could use the benefits of the Application Cache with an online application? The user could access all the resources that they need from the Application Cache instead of the server, and in turn the page would load a lot faster. Another added advantage of using the Application Cache is that there would be a reduced server load and the browser only needs to download anything new instead of fetching the resources that it already has.

Let's get started with the basics of using the Application Cache in an MVC project. In order to enable the Application Cache you need to include the manifest attribute on the HTML tag.

The manifest file can be located anywhere on your web server and contains a list of the things that you want to store in the Application Cache. You could always simply link to a static text file on your server, but I quite like to use the MVC ActionResult and View to return a dynamic manifest file. The browser will continue to use the cached version of the resources until the manifest file has changed or been updated. It can sometimes make debugging your application a nightmare, so if you are reloading your page and find that you are only seeing the cached version - you will need to make a change to the manifest file in order for the browser to fetch the new version.

Right, let's create our dynamic manifest page. Add a new method on your controller - I called mine "Manifest". Notice how the MVC route matches up to the manifest attribute link we supplied on the HTML tag.

Next, add a view for that ActionResult.

Close to the top of the View you will notice a ContentType of "text/cache-manifest". All manifest files must be served with a content type of text/cache-manifest. The manifest file also needs to begin with "CACHE MANIFEST" on the first line.

You should also notice that on that View there is a method called AppendHash(). Thanks to my colleague @ShirtlessKirk for coming up with this idea, this is the Ninja way of handling changing resources.

The method reads the resources and creates a Hash string based on the contents. This way the Hash Key only changes based on whether the resource has changed. This is then appended onto the end of the filename with a Querystring. The Hash Key will only change if the file has changed - this means no updating your manifest file every time a resource (CSS, Javascript, etc.) file has changed! I won't go into too much detail about the class and method that appends the Hash to the file URL, but the whole solution in this article is available for download here.

In order to see the Application Cache in action, let's fire up a browser. I quite like to test with Google Chrome, because the Developer Tools make it quite easy to see what's in the Application Cache. If you hit CTRL-SHIFT-J you should notice the Google Chrome Developer Tools appear. The first time a page loads with the manifest and Application Cache you will notice something like this appearing in the tools console:

As you can see it is downloading the resources that are in the manifest file. If you choose the RESOURCES tab, and then drill down to the Application Cache, you should notice something like this (notice the hash appended):

If we reload the page, all the resources will be loaded from the Application Cache and not be downloaded from the server. Check the Developer Tools console:

An important thing to keep in mind is that any pages that you add the manifest attribute to will be cached in the browser - this INCLUDES THE PAGE ITSELF! You can't just cache the resources and not the page - it's not really designed to work this way. So, the disadvantage of using the Application Cache is that it doesn't play too well with server side dynamic pages. If you think of a website, the pages that you would add to the Application Cache would normally be the pages that are static or pages that don't change that often. If you add the manifest attribute to your Master Page you will cache your entire application and not notice any changes when refreshing - Instead consider only adding this to pages that aren't updated regularly.

For more information on the HTML5 Application Cache, please take a look at this website. If you would like to download the example solution used in this article, please download it here.


Robin Osborne - 7/11/2011
Very nice article. I especially like the AppendHash bit (even if it wasn't your idea ;) I'll be playing around with this shortly, no doubt.

Keith - 7/11/2011
Looks like cached file names cannot contain spaces. I haven't found the HTML5 specification where it states this, but Chrome doesn't seem to like it. Thanks for the article.

Dean Hume - 7/11/2011
@Keith - Thanks for that advice, I didn't know that!

Dan Atkinson - 7/13/2011
Hi Dean, This looks like a really sweet way of doing the manifest. I'm actually very interested in the AppendHash() functionality, and in particular, extending it. I've noticed a few issues with it. Do you know if it's on Github or Google Code at all? Thanks, Dan

Thanigainathan - 7/22/2011
Hi, Can you please tell if this conflicts with the session timeout setting ?

Mike Flynn - 7/22/2011
Funny this was on asp.nets website but IE9 doesn't even support it.

Lee DeLapp - 7/22/2011
@Dean - Thanks! Nice article. Going to give it a try. @Mike - Not sure how ASP.NET and IE9 are related at all... They are different technologies. Unless you are saying that because they are both Microsoft products, there should be inter-related support. ??

jack - 7/24/2011
very good, I come from chengdu of china.

Dan Atkinson - 7/25/2011
Does anyone else hate the way Firefox behaves when it encounters an offline cache? I really hate the fact that it asks for permission to store the static files. I mean, every site doesn't ask you if it can store static content normally, so why would the offline functionality be any different?

Bradley Meck - 8/13/2011
With local database capabilities (localStorage, indexedDb) complex applications can use the application cache for not just page speed and offline viewing, but it also allows for such things as offline document stores that can resync by checking the 'noupdate', 'updateready', or 'error' events.

John Huffman - 10/10/2011
The AppendHash() code was very helpful. I did have to make a couple of tweaks. request.RequestContext is not available in .NET 3.5 so I used System.Web.HttpContext.Current. AppendHash() needs a physical page to calculate the hash, but the manifest needs the route so I added a method.

Jaime Botero - 11/2/2011
I used it on a solution I have deployed in Microsoft Azure and I kept getting 501 errors. After a few hours of troubleshooting I decided to rename the controller from Manifest to AppManifest and that fixed it. I'm assuming Manifest is a reserved word in Azure...

RAJ - 2/24/2012
Hey...Is there anyway i can cache all my views on client side?

Svetlana - 3/19/2012
Hi, guys! Thank you for a very useful article! We`ve just posted an article "How to Cache Images with HTML5" on our blog: Migt be useful for your readers too. Thanks.

@iKUNALrai - 5/1/2012
This example is not working when I deploy it on IIS . Any solution ,sir?

Michael Gois - 4/9/2013
Thank you for posting this, I was having so many problems but the AppendHash technique has made the development cycle so much more reliable!

BacVT - 11/7/2014
The great article , thank you :)

RyanS - 11/19/2015
Out of curiosity, what kind of things are loaded from the "Offline.Utilities" namespace in your Manifest View?

Add your comment

300 Characters left

Please fill this in to confirm that you are human