Caching Content

posted Apr 9, 2012, 12:47 PM by Eric Patrick   [ updated Apr 7, 2014, 4:18 PM ]


Caching speeds application response time and reduces load on the network and server. Use it whenever possible.

QBO 3 leverages two interesting caching technique:
  • Browser caching
  • HTML5 session storage

Browser Caching

When requesting a resource from a server, particularly data-driven content, like this:


The server will typically respond with content headers that look like this:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/7.5
Date: Mon, 09 Apr 2012 19:17:41 GMT
Content-Length: 407

There are times when the data we're requesting will remain static for long periods of time, even if data-driven. For example, a dropdown list of States, or a filter menu for simple table searches frequently do not change during the course of a day. You can tell the browser to cache these items by adding a cache parameter to the query string, like this:


The qbo.Application.HttpHandler will interpret that cache setting, and respond with this:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Expires: Tue, 10 Apr 2012 03:37:19 GMT
Vary: Accept-Encoding
Server: Microsoft-IIS/7.5
Date: Mon, 09 Apr 2012 19:17:19 GMT
Content-Length: 419

If you then navigate to the page later in the day, the browser will not request the resource from the server, but instead will pull it out of cache from the user's hard drive.

HTML 5 Session Storage

Session storage enables using javascript to explicitly store data on a user's hard drive. User may limit the amount of storage, and can turn session storage off. If left on, properly used session storage can greatly enhance the user's experience.

Session storage is built into the qbo3.AbstractObject class. Every time invokeHtml is called, the results are saved in a cache. When a panel is rendered, the qbo3.ObjectBind behavior will attempt to read the panel results from session storage, and will display the results if available. 

Dashboard Example

The Valuation dashboard user experience is:
  • Navigate to the Valuation dashboard (Valuation.ashx/Home
    • There are two panels: a dashboard panel and a search panel
    • On the first visit, neither panel is in session storage
    • The dashboard panel will render the default dashboard by requesting data from the server, and the dashboard results will be saved to session storage
    • The search panel will not be rendered, since no search requests have been issued
  • Click on a link inside the dashboard, rendering the corresponding results in the search panel
    • The search panel will request data from the server, and the search results will be saved to session storage
  • Click on a Valuation hyperlink, navigating away from the Valuation Dashboard
  • Click on a link to revisit the Valuation Dashboard (or just click back)
    • The dashboard panel will render from session storage
    • The search panel will render from session storage, showing the user their last search results
Summary Example

In the Summary, we have to be a bit more careful about our cache. If we are caching, say, an Attachment panel, we must ensure we don't mix the Attachment for Valuation 12345 with those from Valuation 23456. This can be done by specifying a cache key:

<div id="attachmentList" class="span12" data-behavior="ObjectBind" data-objectbind-options="{{ 
  'class': 'qbo3.AttachmentObject', 
  'cacheKey': 'AttachmentList-Valuation-{//ValuationID[1]}', 
  'method': 'Search', 
  'data': {{ 'Object': 'Valuation', 'ObjectID' : '{//ValuationID[1]}' }} 

This ensures that qbo3.js does not mix the cache results for Valuation 12345 with those form Valuation 23456 (or any other ValuationID).

In some cases, it is desirable to cache the panel content for a limited duration. For Summary page panels, it is often reasonable to cache content for 10 minutes, but not all day. The ObjectBind behavior enables a maxCacheDuration setting (measured in minutes) as follows:

<div id="attachmentList" class="span12" data-behavior="ObjectBind" data-objectbind-options="{{ 
  'class': 'qbo3.AttachmentObject', 
  'cacheKey': 'AttachmentList-Valuation-{//ValuationID[1]}', 
  'maxCacheDuration': 10,
  'method': 'Search', 
  'data': {{ 'Object': 'Valuation', 'ObjectID' : '{//ValuationID[1]}' }} 

Caching and Javascript

There are two javascript classes that pay attention to caching:
  • qbo3.AbstractObject
    • options.cacheKey: optional value that controls the key used for session storage and cookie storage
    • options.remember: if true, will attempt to read data from storage; if false, all session storage data is ignored
    • cacheKey(method): a method that returns options.cacheKey if defined, otherwise a combination of the URL, element id, and method
    • readState(method): attempts to read the last known state of a panel from a cookie (using the cache key)
    • readStorage(method): attempts to read the last known results of a panel from session storage (using the cache key)
    • writeStorage(html, script): attempts to store html, scripts, a method and data to session storage (using the cache key)
    • clearStorage(method): deletes data from session storage and cookies
  • qbo3.ObjectBind: writes an HTML div tag to a qbo3.AbstractObject-derived class
    • if the URL contains "&nocache=1", session storage will be cleared
    • if options.remember is true, attempts to load panel content from session storage
This is the most powerful caching available in QBO 3, but it only works with modern browsers (no IE 8 or earlier). Older browsers do not produce an error, they simply ignore cache requests, and re-request everything from the server.

Clearing Cached Resources via Javascript

In some instances, it is desirable to explicitly force the clearing of a cached item. Items cached by the browser may be 'cleared' using the qbo3.reload() method:
  • qbo3.reload('Theme.ashx/Javascript?Version=1')
  • qbo3.reload('Organization.ashx/ListWhere?Tag=MyCompanyList')
For example, a long dropdown list of mortgage servicing Organizations may be used by many forms, and caching significantly improves form load times. However, the form may offer the ability to create a new Organization from the form, invalidating the cached copy of servicers. In such a situation, the form should be coded to:
  • allow the user to create a new Organization, and upon success
  • call qbo3.reload() passing the URL that the mortgage servicing Organization dropdown list uses