Wednesday, January 18, 2012

Creating HTML5 Offline Web Applications with ASP.NET


The goal of this blog entry is to describe how you can create HTML5 Offline Web Applications when building ASP.NET web applications. I describe the method that I used to create an offline Web application when building the JavaScript Reference application.
You can read about the HTML5 Offline Web Application standard by visiting the following links:
Currently, the HTML5 Offline Web Applications feature works with all modern browsers with one important exception. You can use Offline Web Applications with Firefox, Chrome, and Safari (including iPhone Safari). Unfortunately, however, Internet Explorer does not support Offline Web Applications (not even IE 9).

Why Build an HTML5 Offline Web Application?

The official reason to build an Offline Web Application is so that you do not need to be connected to the Internet to use it. For example, you can use the JavaScript Reference Application when flying in an airplane, riding a subway, or hiding in a cave in Borneo.
The JavaScript Reference Application works great on my iPhone even when I am completely disconnected from any network. The following screenshot shows the JavaScript Reference Application running on my iPhone when airplane mode is enabled (notice the little orange airplane):
image

Admittedly, it is becoming increasingly difficult to find locations where you can’t get Internet access.
A second, and possibly better, reason to create Offline Web Applications is speed. An Offline Web Application must be downloaded only once. After it gets downloaded, all of the files required by your Web application (HTML, CSS, JavaScript, Image) are stored persistently on your computer.
Think of Offline Web Applications as providing you with a super browser cache. Normally, when you cache files in a browser, the files are cached on a file-by-file basis. For each HTML, CSS, image, or JavaScript file, you specify how long the file should remain in the cache by setting cache headers.
Unlike the normal browser caching mechanism, the HTML5 Offline Web Application cache is used to specify a caching policy for an entire set of files. You use a manifest file to list the files that you want to cache and these files are cached until the manifest is changed.
Another advantage of using the HTML5 offline cache is that the HTML5 standard supports several JavaScript events and methods related to the offline cache. For example, you can be notified in your JavaScript code whenever the offline application has been updated. You can use JavaScript methods, such as the ApplicationCache.update() method, to update the cache programmatically.

Creating the Manifest File

The HTML5 Offline Cache uses a manifest file to determine the files that get cached. Here’s what the manifest file looks like for the JavaScript Reference application:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
CACHE MANIFEST
# v30
Default.aspx
# Standard Script Libraries
Scripts/jquery-1.4.4.min.js
Scripts/jquery-ui-1.8.7.custom.min.js
Scripts/jquery.tmpl.min.js
Scripts/json2.js
# App Scripts
App_Scripts/combine.js
App_Scripts/combine.debug.js
# Content (CSS & images)
Content/default.css
Content/logo.png
Content/ui-lightness/jquery-ui-1.8.7.custom.css
Content/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png
Content/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png
Content/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
Content/ui-lightness/images/ui-icons_222222_256x240.png
Content/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png
Content/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png
Content/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png
Content/ui-lightness/images/ui-icons_ffffff_256x240.png
Content/ui-lightness/images/ui-icons_ef8c08_256x240.png
Content/browsers/c8.png
Content/browsers/es3.png
Content/browsers/es5.png
Content/browsers/ff3_6.png
Content/browsers/ie8.png
Content/browsers/ie9.png
Content/browsers/sf5.png
NETWORK:
Services/EntryService.svc
http://superexpert.com/resources/JavaScriptReference/
A Cache Manifest file always starts with the line of text Cache Manifest. In the manifest above, all of the CSS, image, and JavaScript files required by the JavaScript Reference application are listed. For example, the Default.aspx ASP.NET page, jQuery library, JQuery UI library, and several images are listed.
Notice that you can add comments to a manifest by starting a line with the hash character (#). I use comments in the manifest above to group JavaScript and image files.
Finally, notice that there is a NETWORK: section of the manifest. You list any file that you do not want to cache (any file that requires network access) in this section. In the manifest above, the NETWORK: section includes the URL for a WCF Service named EntryService.svc. This service is called to get the JavaScript entries displayed by the JavaScript Reference.
There are two important things that you need to be aware of when using a manifest file. First, all relative URLs listed in a manifest are resolved relative to the manifest file. The URLs listed in the manifest above are all resolved relative to the root of the application because the manifest file is located in the application root.
Second, whenever you make a change to the manifest file, browsers will download all of the files contained in the manifest (all of them). For example, if you add a new file to the manifest then any browser that supports the Offline Cache standard will detect the change in the manifest and download all of the files listed in the manifest automatically.
If you make changes to files in the manifest (for example, modify a JavaScript file) then you need to make a change in the manifest file in order for the new version of the file to be downloaded. The standard way of updating a manifest file is to include a comment with a version number. The manifest above includes a # v30 comment. If you make a change to a file then you need to modify the comment to be # v31 in order for the new file to be downloaded.

When Are Updated Files Downloaded?

When you make changes to a manifest, the changes are not reflected the very next time you open the offline application in your web browser. Your web browser will download the updated files in the background.
This can be very confusing when you are working with JavaScript files. If you make a change to a JavaScript file, and you have cached the application offline, then the changes to the JavaScript file won’t appear when you reload the application.
The HTML5 standard includes new JavaScript events and methods that you can use to track changes and make changes to the Application Cache. You can use the ApplicationCache.update() method to initiate an update to the application cache and you can use the ApplicationCache.swapCache() method to switch to the latest version of a cached application.
My heartfelt recommendation is that you do not enable your application for offline storage until after you finish writing your application code. Otherwise, debugging the application can become a very confusing experience.

Offline Web Applications versus Local Storage

Be careful to not confuse the HTML5 Offline Web Application feature and HTML5 Local Storage (aka DOM storage) feature. The JavaScript Reference Application uses both features.
HTML5 Local Storage enables you to store key/value pairs persistently. Think of Local Storage as a super cookie. I describe how the JavaScript Reference Application uses Local Storage to store the database of JavaScript entries in a separate blog entry.
Offline Web Applications enable you to store static files persistently. Think of Offline Web Applications as a super cache.

Creating a Manifest File in an ASP.NET Application

A manifest file must be served with the MIME type text/cache-manifest. In order to serve the JavaScript Reference manifest with the proper MIME type, I added two files to the JavaScript Reference Application project:
  • Manifest.txt – This text file contains the actual manifest file.
  • Manifest.ashx – This generic handler sends the Manifest.txt file with the MIME type text/cache-manifest.
Here’s the code for the generic handler:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Web;
namespace JavaScriptReference {
    public class Manifest : IHttpHandler {
        public void ProcessRequest(HttpContext context) {
            context.Response.ContentType = "text/cache-manifest";
            context.Response.WriteFile(context.Server.MapPath("Manifest.txt"));
        }
        public bool IsReusable {
            get {
                return false;
            }
        }
    }
}
The Default.aspx file contains a reference to the manifest. The opening HTML tag in the Default.aspx file looks like this:
<html xmlns="http://www.w3.org/1999/xhtml" manifest="Manifest.ashx">
Notice that the HTML tag contains a manifest attribute that points to the Manifest.ashx generic handler. Internet Explorer simply ignores this attribute. Every other modern browser will download the manifest when the Default.aspx page is requested.

Seeing the Offline Web Application in Action

The experience of using an HTML5 Web Application is different with different browsers. When you first open the JavaScript Reference application with Firefox, you get the following warning:
image
Notice that you are provided with the choice of whether you want to use the application offline or not. Browsers other than Firefox, such as Chrome and Safari, do not provide you with this choice. Chrome and Safari will create an offline cache automatically.
If you click the Allow button then Firefox will download all of the files listed in the manifest. You can view the files contained in the Firefox offline application cache by typing about:cache in the Firefox address bar:
image
You can view the actual items being cached by clicking the List Cache Entries link:
image
The Offline Web Application experience is different in the case of Google Chrome. You can view the entries in the offline cache by opening the Developer Tools (hit Shift+CTRL+I), selecting the Storage tab, and selecting Application Cache:
image
Notice that you view the status of the Application Cache. In the screen shot above, the status is UNCACHED which means that the files listed in the manifest have not been downloaded and cached yet. The different possible values for the status are included in the HTML5 Offline Web Application standard:
  • UNCACHED – The Application Cache has not been initialized.
  • IDLE – The Application Cache is not currently being updated.
  • CHECKING – The Application Cache is being fetched and checked for updates.
  • DOWNLOADING – The files in the Application Cache are being updated.
  • UPDATEREADY – There is a new version of the Application.
  • OBSOLETE – The contents of the Application Cache are obsolete.

Summary

In this blog entry, I provided a description of how you can use the HTML5 Offline Web Application feature in the context of an ASP.NET application. I described how this feature is used with the JavaScript Reference Application to store the entire application on a user’s computer.
By taking advantage of this new feature of the HTML5 standard, you can improve the performance of your ASP.NET web applications by requiring users of your web application to download your application once and only once. Furthermore, you can enable users to take advantage of your applications anywhere -- regardless of whether or not they are connected to the Internet.


If you liked this blog post then please Subscribe to this blog or Kick It for DotNetKicks.      

No comments:

Post a Comment

Subscribe to RSS Feed Follow me on Twitter!