When relying on resources living on a server, you can increase client app perf & decrease network traffic by storing local versions. When trying to build a sandboxed XBAP, however, you cannot create your own local cache store in the file system beyond the space available in isolated storage (512KB).
Fortunately, WPF resource loading uses System.NET’s HttpWebRequest and its “Default” caching policy. In addition, depending on your resources’ sizes and your scenario, it may make sense to use a non-default caching policy when issuing your own HttpWebRequest.
This post aims to give you a little bit of caching context, an overview of your caching options and some sample code.
Understanding the HTTP Cache
How long is something good for?
This answer is determined through a combination of server & client settings.
The server sets the HTTP Response Header “Expires” to indicate the time after which a resource is considered stale. A stale cache entry may not normally be retrieved unless it is first validated with the origin server as being the current version. In addition, the server may specifiy certain cache directives in the header. These include “no-cache,” “max-age,” and “must-revalidate.”
The client/app’s cache policy can determine whether or not a “stale” or even a “not yet stale” value should be returned. Some of these policies are time based (e.g. “okay if stale only for X days”) or location based (“return cached value if it’s there and meets server specified revalidation requirements.) However whatever the app’s cache policy, it must respect the server’s cache directives.
System.Net’s Cache
System.Net.HttpWebRequest’s cache uses the IE cache. This has many benefits: there is a single place for user management perspective. Also, a shared store widens the chance that a recent response might have already been cached. The IE cache (“inet cache”) uses the Temporary Internet Files (“TIF”) to cache results of HTTP requests. Some details:
System.Net.HttpWebRequest’s cache uses the IE cache. This has many benefits: there is a single place for user management perspective. Also, a shared store widens the chance that a recent response might have already been cached. The IE cache (“inet cache”) uses the Temporary Internet Files (“TIF”) to cache results of HTTP requests. Some details:
- (Update 11 Oct 06)The TIF is by default 3% of the harddrive on XP and 50MB on Vista. This amount is user configurable.
- The TIF is clearable by users through the Internet Options control panel. It is scavenged when full.
- On Vista, IE7 Protected Mode puts Low Integrity Level content in a separate cache.
Understanding the most common cache matrixes
The below table calls out some of the most common caching policies. (Note: We assume that no additional server cache constraints were set other than Expires header.)
Note: If the server does not set the Expires http header, than the expiration=none. In this case, the machine determines what the right “Freshness” time for the resource. By default, this is 1 day but it is configurable.
Note: For System.Net.HttpWebRequest, “Default” policy is somewhat misleading. Unless you explicitly set HttpWebRequest.CachePolicy (or HttpWebRequest.DefaultCachePolicy), the policy is “BypassCache.”
What cache version to use
If your resource files are large & unlikely to change (and having current version is not critical), you should consider:
- Set a large value in your resources HTTP Expires header
- Set cache policy to HttpRequestCacheLevel.Default.
If it is critical to have the current version of the resource, you should consider:
- Set cache policy to HttpRequestCacheLevel.Revalidate.
If you don’t want a unique caching policy, you should stiil:
- Manually set the cache policy to HttpRequestCacheLevel.Default when creating your own HttpWebRequests
How to set cache policy
Here is a code snippet:
// eCreate request HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURI); // Create & set cache policy HttpRequestCachePolicy cachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Default); request.CachePolicy = cachePolicy; // Send request/Get response HttpWebResponse response = (HttpWebResponse) request.GetResponse(); // Put response in to stream Encoding enc = Encoding.GetEncoding(1252); StreamReader responseStream = new StreamReader(response.GetResponseStream(), enc); // Manipulate Response stream // Cleanup response.Close(); responseStream.Close();
Resources to more deeply understand standard caching
- System.NET Cache Management for Networks Applications Overview
- HTTP Protocol RFC 2616 (See sections 13 & 14)
- I’ve also written a small xbap to demonstrate grabbing a text file from the web using the different caching mechanisms. You can run it here or look at the code.
Great article and it helped me figure out the problem with my XBAP application. However I haven’t figured out how to fix it. I have a simple image viewer application and when I create BitmapImage objects with the URI to the hosted image, the cache policy for the BitmapImage is defaulted to bypassCache. I can’t seem to change it and the images get downloaded every time a user clicks on a thumbnail of the image (even if they had previously clicked on it a few seconds ago).
If i set it to a full trust application and then change the HttpWebRequest.DefaultCachePolicy to Default level this behavior is fixed. However you can’t do that for an Internet partial trust application, so I’m stuck with the XBAP loading the full sized image every time the user clicks on the thumbnail. I’m using an in memory cache right now to work around this, but I’d rather let IE cache my data since it has access to a disk drive to write the cache to.
very interesting reading x