• Developer Network
    • Technologies
      • Cloud
      • App Development
      • Web
      • Data
      • Gaming
      • Internet of Things
    • Downloads
      • Visual Studio
      • MSDN subscription access
      • SDKs
      • Trial software
    • Programs
      • Visual Studio subscriptions
      • Students
      • Architects
      • ISV
      • Startups
      • TechRewards
      • Events
    • Community
      • Magazine
      • Forums
      • Blogs
      • Tech Advisors
      • Channel 9
    • Documentation
      • APIs and reference
      • Dev centers
    • Samples
Developer Network Developer
Sign in
MSDN subscriptions
Get tools
magazine
  • Issues and downloads
    • All issues
    • 2016
      • March 2016
      • February 2016
      • January 2016
    • 2015
      • December 2015
      • November 2015
      • Windows 10 issue
      • October 2015
      • September 2015
      • August 2015
      • July 2015
      • June 2015
      • May 2015
      • April 2015
      • March 2015
      • February 2015
      • January 2015
    • 2014
      • Special 2014
      • December 2014
      • November 2014
      • October 2014
      • September 2014
      • August 2014
      • July 2014
      • June 2014
      • May 2014
      • April 2014
      • March 2014
      • February 2014
      • January 2014
    • 2013
      • Government 2013
      • December 2013
      • November 2013
      • October 2013
      • September 2013
      • August 2013
      • July 2013
      • June 2013
      • May 2013
      • April 2013
      • March 2013
      • February 2013
      • January 2013
    • 2012
      • December 2012
      • November 2012
      • Windows 8
      • October 2012
      • September 2012
      • August 2012
      • July 2012
      • June 2012
      • May 2012
      • April 2012
      • March 2012
      • February 2012
      • January 2012
    • 2011
      • December 2011
      • November 2011
      • October 2011
      • September 2011
      • August 2011
      • July 2011
      • June 2011
      • May 2011
      • April 2011
      • March 2011
      • February 2011
      • January 2011
    • 2010
      • December 2010
      • November 2010
      • October 2010
      • September 2010
      • August 2010
      • July 2010
      • June 2010
      • May 2010
      • April 2010
      • March 2010
      • February 2010
      • January 2010
    • 2009
      • December 2009
      • November 2009
      • October 2009
      • September 2009
      • August 2009
      • July 2009
      • June 2009
      • May 2009
      • April 2009
      • March 2009
      • February 2009
      • January 2009
  • Subscribe
  • Submit article
Issues and downloads 2011 November 2011 HTML5 - HTML5 Offline Applications: ‘Donut Hole’ Caching

November 2011
Volume 26 Number 11

HTML5 - HTML5 Offline Applications: 'Donut Hole' Caching

By Craig Shoemaker | November 2011

HTML Offline Applications allow you to create applications that work without an Internet connection using technologies native to the Web browser. Pages included in an offline application are listed in the application manifest and thus are served from the application cache whether a connection to the Internet is present or not. Sometimes, however, if an Internet connection is available, you may want to display some data from the server without requiring the user to change pages.

Scott Guthrie introduced the concept of “donut hole” caching in ASP.NET, where a cached page may include small windows of content that are updated independently of the cached page. This tutorial demonstrates how to implement an offline page that makes an AJAX call when connected to the Web in order to display live data to the user. When offline, the page simply renders default data in the page.

There are a number of practical reasons to implement an offline application. While most developers first think of the mobile context when considering who might use an offline application, almost any Web site can benefit from having some availability regardless of connection status. A site’s Home and Contact Us pages are excellent candidates for offline availability so users can get some basic information about the organization, even when disconnected.

Building the Application

The example in this tutorial demonstrates how to cache a “Contact Us” page that displays notifications of upcoming events to users. When a user is connected to the Web, live event listings are displayed; otherwise, a telephone number prompts the user to call for event information. This approach keeps the user informed and connected with or without access to the public Web.

Figure 1 depicts how the page is rendered for offline viewing, while Figure 2 shows how the page looks when served from the application cache but the computer is connected to the Web.

When the User Is Working Offline, the Application Prompts Him to Call for Event Information
Figure 1 When the User Is Working Offline, the Application Prompts Him to Call for Event Information

 

When the User Is Connected to the Internet, the Application Shows Event Information from the Server
Figure 2 When the User Is Connected to the Internet, the Application Shows Event Information from the Server

The Manifest

The application manifest acts as the master list of resources included in the offline application. Figure 3 shows the full manifest file for this example.

Figure 3 Manifest File (manifest.aspx)
XML
Copy
CACHE MANIFEST
# version 1
CACHE:
contact.htm
style.css
jquery-1.6.3.min.js
map.png
NETWORK:
events.htm
<%@Page
    ContentType="text/cache-manifest"
    ResponseEncoding = "utf-8"
    Language="C#" AutoEventWireup="true"
    CodeBehind="manifest.aspx.cs"
    Inherits="ConditionalCaching.manifest" %>
<script language="CS" runat="server">
  void Page_Load(object sender, System.EventArgs e)
    {
      Response.Cache.SetCacheability(HttpCacheability.NoCache);
    }
</script>

The file begins with the requisite CACHE MANIFEST header and includes a versioning comment to allow changes in listed files to propagate to the client.

Next, the CACHE section references the contact page intended to be available to users regardless of connection status. The contact page references a style sheet, jQuery and a map image indicating the physical office location.

Finally, the NETWORK section is needed in this instance to ensure access to the events.htm page (shown in Figure 4). The reason this page isn’t included in the CACHE section is because in the real world the events page would be built dynamically as a server-generated page. Caching a page like this would defeat the purpose of making live event data available to the user when connected to the Web. With the events page listed in the NETWORK section rather than the CACHE section, the Application Cache API won’t attempt to cancel the request to the page. Ultimately, the page’s inclusion in the NETWORK section tells the browser to always attempt to fetch the page from the Web regardless of connection state.

Figure 4 Events Page (events.htm)
XML
Copy
<table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td>Aug 15</td>
    <td><a href="/events/anaheim">Anahiem Convention Center</a></td>
  </tr>
  <tr>
    <td>Sept 5</td>
    <td><a href="/events/los-angeles">Los Angeles Convention Center</a></td>
  </tr>
  <tr>
    <td>Oct 3</td>
    <td><a href="/events/las-vegas">Las Vegas Convention Center</a></td>
  </tr>
  <tr>
    <td>Nov 14</td>
    <td><a href="/events/denver">Colorado Convention Center</a></td>
  </tr>
</table>

Note that the manifest is implemented as an ASPX file in order to disable browser caching of the file. You may prefer to disable caching on the Web server via configuration settings, but this approach is used here to make the sample code more portable for demonstration purposes.

The Contact Us Page

The contact page HTML, shown in Figure 5, is implemented as you might expect regardless of whether the page is being optimized for offline access. The most important detail to note in the HTML for the page is the contents of the paragraph with the ID of localMessage. This container holds the content that’s displayed when the user is working offline; that content is replaced on-the-fly when a connection to the Internet is available.

Figure 5 Contact Page (contact.htm)
XML
Copy
<!DOCTYPE html>
<html manifest="manifest.aspx">
<head>
  <title></title>
  <link rel="Stylesheet" href="style.css" type="text/css" />
  <script src="jquery-1.6.3.min.js" type="text/javascript"></script>
  <script>
    $(function () {
      window.applicationCache.onupdateready = function (e) {
        applicationCache.swapCache();
        window.location.reload();
      }
      function isOnLine() {
        //return false;
        return navigator.onLine;
      }
      function showEventInfo() {
        if (isOnLine()) {
            $("#localMessage").hide();
            $.get("/events.htm", function (data) {
                $("#eventList").html(data);
                $("#eventList table tr:odd").addClass("alt");
            });
        }
        else {
          $("#localMessage").show();
        }
      }
      showEventInfo();
    });
  </script>
</head>
<body>
  <div id="container">
    <h1>Awesome Company</h1>
    <h2>Contact Us</h2>
    <p>
      Awesome Company<br />
      1800 Main Street<br />
      Anytown, CA 90210<br />
      (800) 555-5555<br />
      <a href="mailto:awesome@company.com">awesome@company.com</a>
    </p>
    <img src="map.png" />
    <div id="events">
      <h2>Events</h2>
      <p>We are coming to a city near you!</p>
      <p id="localMessage">Give us a call at (800) 555-5555
        to hear about our upcoming conference dates.</p>
      <div id="eventList"></div>
    </div>
    <div id="version">Version 1</div>
  </div>
</body>
</html>

Note that in the script section of the page, all functions are defined and run nested in the jQuery document-ready handler:

XML
Copy
$(function () {
    ...
});

The first order of business is to process any updates to the page loaded in the application cache by handling the updateready events. If the application manifest changes, all the files listed in its CACHE section are copied to the client. When new versions of the files are available, the updateready event fires and the page can load the latest version of the contact page from the cache by calling applicationCache.swapCache. Finally, once the latest version is loaded into memory, the page is reloaded in order to display the changes to the user:

XML
Copy
window.applicationCache.onupdateready = function (e) {
  applicationCache.swapCache();
  window.location.reload();
}

Next, the page needs a mechanism to detect whether the computer is working in a connected or disconnected state. The isOnLine function simply wraps up a call to the read-only navigator.onLine Boolean property. This encapsulation is handy because, should you want to override the value for testing purposes, you can un-comment the return false line and test the page’s offline behavior without having to actually disconnect from the Web:

XML
Copy
function isOnLine() {
  //return false;
  return navigator.onLine;
}

By the way, using navigator.onLine as the sole mechanism for detecting online status is a bit rudimentary. For a more robust way to detect online status, please read the tutorial, “Working Off the Grid with HTML5 Offline,” by Paul Kinlan.

The showEvent function is responsible for implementing the “donut hole caching” functionality for the HTML offline application. The function first detects the connection status of the computer and then either fetches and renders live event data or just shows the event information that already exists in the page.

If the isOnLine function returns true, the local message is hidden from the user and an AJAX call to the events page is initiated. When a response from the asynchronous call is recognized, the resulting HTML is fed to the eventList container and the table is styled with zebra striping.

If, on the other hand, the computer is working offline, the local message is displayed to the user like so:

XML
Copy
function showEventInfo() {
  if (isOnLine()) {
      $("#localMessage").hide();
      $.get("/events.htm", function (data) {
        $("#eventList").html(data);
        $("#eventList table tr:odd").addClass("alt");
      });
  }
  else {
    $("#localMessage").show();
  }
}

Finally, the manifest file is referenced at the top of the HTML page by populating the manifest attribute of the html element pointing to the manifest file:

XML
Copy
<html manifest="manifest.aspx">

Figure 6 shows the style.css file that’s listed in the manifest and referenced by the contact page.

Figure 6 Style Sheet (style.css)
XML
Copy
body
{
  font-family:Segoe UI, Arial, Helvetica, Sans-Serif;
  background-color:#eee;
}
h1
{
  text-transform:uppercase;
  letter-spacing:-2px;
  width:400px;
  margin-top:0px;
}
#container
{
  position:relative;
  margin-left:auto;
  margin-right:auto;
  padding:20px;
  width:700px;
  -webkit-box-shadow: 3px 3px 7px #999;
  box-shadow: 6px 6px 24px #999;
  -moz-border-radius: 10px; 
  -webkit-border-radius: 10px;
  border-radius: 10px;
  margin-top:20px;
  background-color:#fff;
}
#events
{
  position:absolute;
  width:210px;
  right:20px;
  top:255px;
  border:1px solid #ccc;
  padding:10px;
  font-size:.7em;
  background-color:#eee;
}
#events h2
{
  margin:0px;
}
#version
{
  font-size:.7em;
  color:#ccc;
}
table
{
  border-collapse:collapse;
}
table, tr, td
{
  border:1px solid #999;
}
.alt
{
  background-color:#ccc;
}

Wrapping Up

Even though pages loaded into the application cache are served from the cache whether the computer is connected to the Internet or not, you can construct your pages to take advantage of online resources when they’re available. “Donut hole caching” works by making an AJAX call to the server when a connection is available and then rendering the results to the user. If the page is in a disconnected state, the application quietly renders data already available on the page—it’s the best of both worlds!

Resources

  • HTML Offline Web Applications Specification
  • Using Application Cache
  • Go Offline with Application Cache
  • Tip/Trick: Implement “Donut Caching” with the ASP.NET 2.0 Output Cache Substitution Feature
  • A Beginner’s Guide to Using the Application Cache
  • Working Off the Grid with HTML5 Offline
  • HTML5 Rocks: Offline Tutorials

Craig Shoemaker  is a software developer, podcaster, blogger and product guidance manager for Infragistics. As host of the Polymorphic Podcast and Pixel8, Shoemaker does what he loves most—making contributions to the community and drawing the best out of industry luminaries. Shoemaker is a Microsoft ASP.NET MVP, ASP Insider and guest speaker at various developer user groups and tradeshows. He’s coauthor of “Beginning ASP.NET 2.0 AJAX” (Wrox, 2007) and “Beginning ASP.NET AJAX” (Wrox, 2006), and a contributing author to Pluralsight, TekPub and CODE Magazine. In his spare time Shoemaker enjoys looking for a haystack in which to hide his prize needle collection. You can contact him on Twitter @craigshoemaker or by e-mail CShoemaker@infragistics.com.




About the Author
   

MSDN Magazine Blog

14 Top Features of Visual Basic 14: The Q&A
Wednesday, Jan 7 by Michael Desmond - MSDN Magazine
Big Start to the New Year at MSDN Magazine
Friday, Jan 2 by Michael Desmond - MSDN Magazine

More MSDN Magazine Blog entries >


Current Issue


March 2016 issue

Browse All MSDN Magazines


Subscribe to the MSDN Flash newsletter Subscribe to MSDN Flash newsletter


Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.

Follow us
  • http://www.facebook.com/microsoftdeveloper
  • https://twitter.com/msdev
  • http://plus.google.com/111221966647232053570/
Sign up for the MSDN Newsletter
Was this page helpful?
Your feedback about this content is important.
Let us know what you think.
Additional feedback?
1500 characters remaining
Thank you!
We appreciate your feedback.
Dev centers
  • Windows
  • Office
  • Visual Studio
  • Microsoft Azure
  • More...
Learning resources
  • Microsoft Virtual Academy
  • Channel 9
  • Interoperability Bridges
  • MSDN Magazine
Community
  • Forums
  • Blogs
  • Codeplex
Support
  • Self support
Programs
  • BizSpark (for startups)
  • DreamSpark
  • Imagine Cup
United States (English)
  • Newsletter
  • Privacy & cookies
  • Terms of use
  • Trademarks
© 2016 Microsoft