0 Comments

Windows Phone caches web requests aggressively. We’ve all seen a case where the first request to the web server works as expected but then the following requests fail to return up-to-date data. Instead of just adding the timestamp to the request URL, you can fix this issue on the server side.

Background

Here’s a simple app next to Fiddler which demonstrates the problem. The app issues a web request with every button click:

        private async void DoRequest_OnClick(object sender, RoutedEventArgs e)
        {
            var client = new WebClient();
            await client.DownloadStringTaskAsync("http://adafy.com");

            requestCount += 1;

            this.RequestCount.Text = requestCount.ToString();
        }

First, a screenshots where user has clicked the button the first time:

image

And here’s what happens when she clicks the button the second time:

image

As you can see from the Fiddler, no request is sent to the server: Windows Phone returns the web request’s response from the cache.

The most often seen solution to this is to add a timestamp to the URL, this way bypassing the Windows Phone’s caching mechanisms. Example:

image

The requested URL changes every time, this way bypassing Windows Phone’s caching.

Solution

All this is because of the web request’s response headers.Make the server return the following Cache-Control header and your app will work exactly as you want:

Cache-Control: public, max-age=15, must-revalidate

Where max-age defines how long (in seconds) your Windows Phone app will cache the request.

By changing the headers you can configure how the app behaves. For example:

  1. You can force your app to make a fresh request every time (set max-age to 0).
  2. You can set exact caching (in seconds) for the requests.

Setting the headers on ASP.NET MVC

ASP.NET MVC offers multiple ways of configuring cache-control header. For example you can set the header on every action:

Response.Headers.Set("Cache-Control", "public, max-age=15, must-revalidate");

Or you can create a filter which is automatically executed after each request. The following StackOverflow questions show multiple solutions:

http://stackoverflow.com/questions/7087859/how-do-i-add-site-wide-no-cache-headers-to-an-mvc-3-app

http://stackoverflow.com/questions/9234044/asp-net-mvc-and-ie-caching-manipulating-response-headers-ineffective

Setting the headers on Azure Blob Storage

If you use Azure Blob Storage as your app’s backend, you can set caching for each blob using the blob.SetProperties-method:

            var blob = container.GetBlockBlobReference(file);
            blob.UploadText(content);

            blob.Properties.CacheControl = string.Format("public, max-age={0}, must-revalidate", (int)cacheAge.TotalSeconds);
            blob.Properties.ContentType = contentType;

            blob.SetProperties();

8 Comments

There’s two ways to use storage in Windows Phone 8 apps:

  • Isolated Storage
  • Windows.Storage

So which one should you use? My recommendation: Windows.Storage.And why? Because Isolated Storage isn’t thread safe.

When the app is small and there’s no 3rd party libraries, you can create a wrapper over the Isolated Storage which uses locking to make sure that only one thread can access the Isolated Storage. But as soon as you add a third party library, you’ll lose control: If the library uses Isolated Storage, it will bypass the locking mechanism you have created inside your storage wrapper.

So, in order to save yourself from random exceptions and strange data losses, prefer Windows.Storage over Isolated Storage.

2 Comments

Sometimes when you try to debug a Windows Phone app through emulator with Visual Studio, you may encounter the following error:

A specified communication resource (port) is already in use by another application

image

One possible reason for this is that Visual Studio tries to debug an app which isn’t deployedto the emulator.

For example, if you set the startup project like this:

image

And then through Visual Studio’s Configuration Manager you don’t check the “Deploy” for this particular project:

image

You will get the error when launching the debugger.

0 Comments

There’s multiple ways to pass data between pages in Windows Phone apps. Most frequently used ways include:

  • Query strings
  • Application state
  • Static properties in App.xaml.cs

One alternative, which I haven’t seen discussed that much, is Application.Resources. Using Application.Resources has these benefits:

  • You can store almost anything in there, including complex objects (List<Customer> etc.)
  • Application.Resources can be accessed from anywhere. You can split the app into multiple assemblies and all these can access Application.Resources.
  • It’s easy to use

Usage

The simple “pattern” for using Application.Resources to pass data between pages looks like this:

  1. Call Application.Current.Resources.Add (mydata, “mykey”) to add the data
  2. Navigate to an another page
  3. Call Application.Current.Resources[“mykey”] to retrieve the data

Example

Store the data before navigation:

            var customers = GetCustomers();
            Application.Current.Resources.Add("NavigationParam", customers);

            NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));

Retrieve the data after navigation:

            var customers = (List<Customer>) Application.Current.Resources["NavigationParam"];

Helper

This process can be made even easier with a simple helper. With it, you could write the following code to store the data:

            var customers = GetCustomers();
            ParameterHelper.Store(customers);

And the following code to retrieve it:

            var customers = ParameterHelper.Get<List<Customer>>();

Notes

  • The data is lost if the application is tombstoned.
  • If there already exists data in Application.Resources with key “NavigationParam” and you try to add new data with the same key, an exception is thrown. Always remember to remove the existing data.

Example project

An example project (which includes the ParameterHelper) is available from GitHub (folder windows-phone-application-resources-navigation).

Portable Class Libraries are a great way to share common code between different platforms. But here lies the danger: A portable class library project cannot change the underlying platform.

Here’s a simple explanation of what that means.

Example project

The example application is built for Windows Forms, Windows RT and Windows Phone. The authentication mechanism is identical in every app so that is placed in a Portable Class Library project:

    public class WebTool
    {
        public async Task<string> GetAuthenticationKey()
        {
            var cookieContainer = new CookieContainer();
            var client = new HttpClient(new HttpClientHandler() { CookieContainer = cookieContainer });

            // Authenticate with the service
            await client.GetStringAsync("http://cookietest.api.domain.com/cookie/get");

            // Return the received cookie as authentication key
            var cookieHeader = cookieContainer.GetCookieHeader(new Uri("http://cookietest.api.domain.com/"));

            return cookieHeader;
        }
    }

Using this library doesn’t get easier: Each platform can call it with identical code:

            var webTool = new WebTool();

            var result = await webTool.GetAuthenticationKey();

            if (string.IsNullOrWhiteSpace(result))
                this.Result.Text = "Didn't receive authentication key!";

            else
                this.Result.Text = "Authentication key: " + result;

Few minutes and everything is done, so the testing phase begins.

First, Windows Forms:

image

Then Windows 8:

image

And last but not least, Windows Phone:

image

Uh oh.

Cookies and CookieContainer especially are different beasts in different platforms. Portable Class Library cannot hide that fact.

Have you encountered similar issues when dealing with Portable Class Library projects?