Windows Phone 7 and WebClient

Inspired by Rob Tiffany’s great series of articles around Windows Phone 7 Line of Business Application Development I started playing with a Windows Phone 7 Client / Azure Service combination. Since I really want to understand what is happening under the hood, my samples are usually extremely simple, yet explaining a lot about the used technology. Developing Windows Phone 7 applications however often makes me feel blind and curious. As an application developer, Windows Phone 7 appears much as a black box. Of course I know that I am running a managed application inside a Sandbox, but it would be able to sometimes take a look inside the box. Take the following scenario:

I have created a small WCF based Azure REST service. It has the following extremely simple functionality:

  • Store a single numeric value (BaseURI/setdata?number={value})
  • Retrieve the stored value (BaseURI/getdata)

I also created a Windows Phone 7 application that can used this service to store / retrieve a single number. Retrieving data from the service can be done using the following code snippet:

  1. private void GetWithLocalWebClient(object param)
  2. {
  3.     WebClient wc = new WebClient();
  4.  
  5.     wc.BaseAddress = IsDevice ? azureServerBaseAddress : localServerBaseAddress;
  6.     wc.DownloadStringCompleted +=
  7.         new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
  8.     wc.DownloadStringAsync(new Uri("getdata", UriKind.Relative));
  9. }
  10.  
  11. void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
  12. {
  13.     WebClient wc = sender as WebClient;
  14.     if (wc != null)
  15.         wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
  16.     RawRESTServiceData = e.Result;
  17. }

In this code snippet, each time the number is retrieved from the service, a new object of type WebClient is created that is used only once. The code to store a number in the cloud is very simple as well:

  1. private void SetNumber(object param)
  2. {
  3.     webClient.UploadStringAsync(
  4.         new Uri("setdata?number=" + Number, UriKind.Relative), string.Empty);
  5. }

To store a number, I am using another instance of WebClient, with a base URL set. This same instance can also be used to retrieve the number from the service, so my application has the possibility to retrieve a single number from an Azure hosted web service in different ways.

RetrieveCachedWhile testing the application, I started by retrieving the number that is currently stored in my Azure service, followed by storing a new number in the cloud and again retrieving the number that is currently stored. As you can see in the following screen dump, the last retrieval came with an unexpected result (1 instead of 3). Where did my stored number go?

It turns out that the WebClient is caching data, and it appears it does so to the extreme. Even if I create a new WebClient, it still uses cached data which is a complete surprise to me. On one hand this seems like a good thing, because it will result in less calls being made to the cloud, thus saving valuable resources. At the same time, it seems like a bad thing. What if my cloud data is updated and I still want to retrieve it through a REST call? Especially when creating a new WebClient object I think it would be reasonable to assume that a ‘real’ call will be made to my Azure service.

To resolve this potential issue, there is an easy solution. Just decorate the REST call with a unique string. Of course I don’t want to do this always, since that means that I am always physically calling out to the service. By re-using the last decorated REST call until I want to force a refresh of my data, I kind of have the best of both worlds available.

  1. private void GetCachedWithUri(object param)
  2. {
  3.     webClient.DownloadStringAsync(cachedUri);
  4. }
  5.  
  6. private void GetUncached(object param)
  7. {
  8.     cachedUri = new Uri("getdata?ticks=" + Environment.TickCount, UriKind.Relative);
  9.     webClient.DownloadStringAsync(cachedUri);
  10.     HasSavedUri = true;
  11. }

RetrieveUncached

 

Retrieving the data from the service without caching gives the expected result. Be aware though that the original cached data is still stored, so retrieving cached afterwards again gives us the original (cached) value.

 

Be aware of this behavior inside your own applications. The following video explains the caching behavior of the WebClient class in more detail:

WebClient caching behavior on Windows Phone 7

This explanation ofthe WebClient caching behavior will hopefully help you creating better Windows Phone 7 applications and save you time trying to understand what is going on behind the scenes.

Advertisements
Both comments and trackbacks are currently closed.
%d bloggers like this: