TLDR: Windows Phone 7.1 Mango's Image control now respects HTTP/1.1 server cache directives, and particularly the max-age, meaning better performing apps. And it is doing it better than you could ever do :)

Image loading is one of the weakest parts of third party apps on Windows Phone 7.0 (NoDo).

The Flickr app in WP7 is a good demonstration of this. The app is basically stalling during the loading of images, and there are (obviously) a lot of images loaded by this app. (The Mango release will make this app really awesome and responsive, I can tell you :))

There are two main reasons for this, being the image loading happening on the UI Thread and partial cache persistence.

 

Hacking around image loading in NoDo

So if you look around to mitigate those two issues, you'll find a few things like the LowProfileImageLoader from a Microsoftee. This removes a lot of burden from the UI thread by not using the WebClient, and queueing requests to avoid having too many dowloads at the same time.

But like I've discussed before, this is still not the perfect solution because HttpWebRequest still goes on to the UI thread, and when there are many images loaded the UI becomes easily sluggish.

For the image cache part, Silverlight will cache BitmapImage instances based on the Url, will persist them across application runs but will ignore the HTTP/1.1 max-age directive. This means that each time you run the application, the app will try to refresh the image again. It may not be downloaded again, but it still is checked. This may delay a lot the display of the image, because of the wait for the server to check if the image has changed.

If you still want to do some sort of caching without asking the server every time, then you need to handle the storage of downloaded streams and use BitmapSource.SetSource, and perform some in-memory caching of BitmapSource instances to still use the Silverlight cache even if you can't provide an Url. And all this has to be performed on the UI thread. It really does not help.

These are many roadblocks that hurt badly the perceived performance of the application.

 

Images in Mango

If you try to the same in Mango, doing the background download and caching by yourself, you end up making the matters worse.

Mango has changed everything on that front, and the Product Team has addressed these issues in a very nice way. Loading images is now seamless, you can download as many as you want and UI will not lag a bit.

If you observe the loading of images in mango, you'll quickly see that cached images are displayed almost instantly, primarily because of the cache engine respecting server cache directives. This means that an image will not be checked for a refresh nor downloaded again if the cache duration has not expired.

All this means that you pretty much don't need to do anything to display images in Mango, unless you need to bypass server caching directives.

This is good news :)

Also, Silverlight seems to be doing some work off the UI thread the "user code" (us, mere mortals) cannot do because it needs to be on the UI thread, meaning that you have to let Silverlight do its magic to load images the fastest and seamless way possible.

 

Image caching in Mango

By looking closer to the way Mango does caching, I've noticed a few things :

  • Images seem to be downloaded once per application run, meaning that server cache directives are ignored until a restart of the application (Fast-resume does not seem to count as a restart),
  • Images that need to be refreshed are checked for modifications on the server, and if an HTTP 302 is sent back, the cached image stays.
  • ETag is supported, the If-None-Match header is sent when the max-age has been reached.
  • If-Modified-Since is also sent when the max-age time span has been reached,
  • When using BitmapCreateOptions.IgnoreImageCache
    • Server cache directives do not seem to be bypassed, the cache is not refreshed until max-age has been reached
    • If Cache-Control max-age and Expires headers are not specified the cache does not seem to be ever refreshed
    • If Expires is specified but not max-age, then the server is called to check for a newer version with If-Modified-Since

These are very good news, since most web server implementation support and respect the HTTP/1.1 Cache-Control directives, meaning that images will be displayed and refreshed properly by default.