Thursday, January 31, 2013

Serve up a HTML5 Cache Manifest using ASP.NET MVC

I’ve been working on some mobile HTML5/jQuery Mobile applications that allow for running offline. The magic that allows for offline web apps is HTML5’s cache manifest, which tells the browser which resources, HTML, images, scripts, etc. to store on the device, and which it is allowed to access over the devices network connection.  The format for this file is fairly straightforward:

CACHE MANIFEST
#comments here
NETWORK:
#Urls that the app is allowed to access
*
CACHE:
#Urls that the app should store in cache. 
/index.html
/someimage.png
/somescript.js

However, two gotchas can make working with it difficult.  First, it must be served up with a particular content type, “text/cache-manifest”, that is not always enabled on web servers.  That involves some server-side tweaks, which can be tricky if you don’t have access to the server.  Second, it should change anytime your app changes, so that the browser knows to re-load the resources.  However, often if you change code or markup inside a file, you may forget to update your cache manifest.  Or at least I did enough to come up with this alternative.

Instead of a static manifest, I serve one up via a MVC action.  The action includes the assembly version and a file timestamp so that it is always versioned automatically with any change to the app.

public ActionResult Manifest()
{
var manifest = "CACHE MANIFEST" + Environment.NewLine +
      "# App Markup Date: " + System.IO.File.GetLastWriteTime(Server.MapPath("~/Views/Mobile/Index.cshtml")) + Environment.NewLine +
      "# Server Assembly Version: " + this.GetType().Assembly.GetName().Version + Environment.NewLine +
      "NETWORK:" + Environment.NewLine +
      "*" + Environment.NewLine +
      "CACHE:" + Environment.NewLine +
      Url.Action("Index", "Mobile") + Environment.NewLine +
      Url.Content("~/content/jquery.mobile-1.2.0.min.css") + Environment.NewLine +
      Url.Content("~/scripts/jquery-1.8.3.min.js") + Environment.NewLine +
      Url.Content("~/scripts/jquery.mobile-1.2.0.min.js") + Environment.NewLine +
      Url.Content("~/scripts/knockout-2.2.0.js") + Environment.NewLine +
      Url.Content("~/content/images/icons-18-white.png") + Environment.NewLine +
      Url.Content("~/content/images/ajax-loader.gif") + Environment.NewLine;
 
return Content(manifest, "text/cache-manifest");
}

This assumes a single page application, but could be easily adapted to add additional dependencies.  Using on an application simply involves adding the following to your view:

<html manifest="@Url.Action("Manifest", "Mobile")">

4 comments:

Balaji Pg said...

Hi Daniel,Could you please tell how to configure the Mime type in IIS for this implementation?

Daniel Root said...

With this implementation, you don't have to configure the Mime Type in IIS. MVC is setting that HTTP Header when you return Content(manifest, "text/cache-manifest"). If you choose not to use this method, and just want to host a .appmanifest file in IIS, you need to follow these steps and specify .appmanifest filetype with text/cache-manifest content type: http://technet.microsoft.com/en-us/library/cc725608(WS.10).aspx

Arsman Ahmad (MaaN) said...

Not working in my case. I don't know why. :-(

Mike Devenney said...

Thanks Daniel! Years later, but it still works just fine.