How to fool a Store App’s image cache

Images displayed within a Windows Store App are generally cached, in order to reduce data transfer (in case of online images) and rendering effort. This caching is done automatically by the framework, which is a good thing as developers need not care about those performance enhancing tasks, but at the same time is a bit dangerous as it might leed to unexpected display errors or rendering issues.

Technically, image caching seems to be implemented in a rather simple way: When loaded for the first time, images are stored locally in conjunction with the URI it was retrieved from (to be exact, within the AC folder in the App’s local storage folder. Whenever the same URI is queried again (within a predefined range of time, obviously), the cached image is displayed instead of the original one.

This applies to both images referenced from the web (using a public URL) or from the device’s storage (through a local Uri that follows the ms-appdata:/// scheme) – and in both cases, this might result in problems, e.g. when:

  • querying an old-fashioned web cam that delivers single images once every few seconds: Typically, the URI won’t change, bot you’ll need the current image to be loaded from the web, not from the local cache
  • displaying a local image that is contantly re-generated by an external process

A simple approach towards the first use-case is to fake a unique URI by adding arbitrary URI parameters, e.g.:

Random rnd = new Random();
Image.Source = new Uri("http://randomserver/someimage.png" + "?abc=" + rnd.Next(1000, 9999);

Just make sure you use random numbers big enough to produce different results each time with a sufficiently high probability. Alternatively, this approach can also be used to control the image cache lifetime, by simply adding a timestamp instead of a random number to the URI. E.g., to simulate a local cache that is emptied once a day, add the current day (as unique number) as URI parameter:

var day = DateTime.Now.DayOfYear.ToString();
Image.Source = new Uri("http://randomserver/someimage.png" + "?cache=" + day;

A more elegant solution is the usage of the .NET framework’s built in cache options. Confusingly enough, this is not done through the Image control’s CacheMode property, but rather by setting the BitmapImage.CreateOptions property:

<Image>
	<Image.Source>
		<BitmapImage UriSource="{Binding Uri}" CreateOptions="IgnoreImageCache"/>
	</Image.Source>
</Image>

The meaning of the IgnoreImageCache enum value should be self-evident. To not be forced to create this nested XAML code each time a picture is referenced, we can alternatively define a converter that does the trick, and can then be referenced by all Image controls that should bypass the image cache:

public class UncachedImageConverter : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, string language)
	{
		var uri = value as Uri;
		if (uri != null)
		{
			var bitmap = new BitmapImage();
			bitmap.UriSource = uri;
			bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
			return bitmap;
		}
		return DependencyProperty.UnsetValue;
	}

	public object ConvertBack(object value, Type targetType, object parameter, string language)
	{
		throw new NotImplementedException();
	}
}