Skip to main content

WP7Contrib: Timing out HTTP requests on Windows Phone 7

This code uses change set #68097 of the WP7Contrib - http://wp7contrib.codeplex.com/SourceControl/changeset/changes/68097

When doing communications over HTTP we often want to set a timeout for the response.  We want the ability to handle the timeout in a timely manner when the communication with a remote server has taken too long. When using the full version of the .Net framework we have the ability to control this precisely using the HttpWebRequest.Timeout property. The default value is set to 100 seconds. Unfortunately the ability to change this property is not supported on the Windows Phone 7 platform and I suspect the value is set to 100 seconds (should test this hypothesis). Looking around on the internet there are several approaches to get around this problem using the DispatcherTimer class and explicitly disposing of the request when the timeout has been exceeded, see an example here.

When using our ResourceClient to do RESTful communication over HTTP we can leverage the power of Rx (reactive extensions) and use the 'Timeout()' method - nice simple example here. This method throws a TimeoutException when the timeout occurs.

The following example shows the implementation for the button click code-behind using the previous ResourceClient example (Google Weather API on WP7):

private void button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
      this.weatherResource.Get<xml_api_reply>(encoder.Encode(location.Text))
         .Timeout(TimeSpan.FromMilliseconds(10000))
         .ObserveOnDispatcher()
         .Subscribe(result =>
            {
               var text = string.Format("Current Temp. (Celsius) in {0}: {1}",
               location.Text,
               result.weather[0].current_conditions[0].temp_c[0].data);
            
               Debug.WriteLine(text);
            },  
            exn => Debug.WriteLine("Failed, exception - " + exn.Message),
            () => Debug.WriteLine("Completed!"));
}

When executed the code outputs the following in Visual Studio:


To demonstrate a timeout we can lower the value to 10 ms, this gives the following output in Visual Studio:


Now setting a 'reasonable' value this should cover 90% of cases, but there are going to be times when we will receive timeout exceptions unexpectedly.  When this happens we want to employ a retry strategy, again Rx provides a method for this - 'Retry()'. Shown below is the code with a retry strategy of 3 attempts:

private void button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
      this.weatherResource.Get<xml_api_reply>(encoder.Encode(location.Text))
         .Timeout(TimeSpan.FromMilliseconds(10))
         .Retry(3)
         .ObserveOnDispatcher()
         .Subscribe(result =>
            {
               var text = string.Format("Current Temp. (Celsius) in {0}: {1}",
               location.Text,
               result.weather[0].current_conditions[0].temp_c[0].data);
            
               Debug.WriteLine(text);
            },  
            exn => Debug.WriteLine("Failed, exception - " + exn.Message),
            () => Debug.WriteLine("Completed!"));
}

When executed the code outputs the following in Visual Studio:


The above shows 3 attempts to access the remote server and we finally see the exception bubbling up and being handled.

Now we have to decide what a 'reasonable' value for timeout is and I believe this is dependent on the application you're building and the remote (back end) services you're using. If you're communicating with an enterprise level back end  (e.g. Google API) then you're going to be able to get away with a lower value. I would start with a value around  60 seconds and do testing in the field.  When choosing a value, it is impolrtant to remember that the maximum amount of time for making a request is going to be:

        Time out x Retry = Maximum total time.

         20 secs x 3 = 60  secs

So a user could be waiting for 60 seconds for data to be returned and displayed.

There is one caveat to this strategy and that is the hard coded value used by the HttpWebRequest class. If as I suspected this is hard coded to 100 secs as described by MSDN for the desktop version of .Net, then we will not be able to set a timeout greater than 100 secs.  I've not been able to test this just yet.

So the code examples above demonstrate the use of timeout & retry with the ResourceClient directly in the code-behind.

I've also updated the weather service implementation and what you now start seeing is the cleaner approach of using the service from the code-behind (or ideally from a view model) - the service is responsible for managing the retry strategy and the code-behind use of the service has not been modified.

You can find the demo application 'CommunicationTimeout' in the Spikes directory of the WP7Contrib code base. Shown below is a screenshot from the demo application.







Comments

Popular posts from this blog

WPF tips & tricks: Dispatcher thread performance

Not blogged for an age, and I received an email last week which provoked me back to life. It was a job spec for a WPF contract where they want help sorting out the performance of their app especially around grids and tabular data. I thought I'd shared some tips & tricks I've picked up along the way, these aren't probably going to solve any issues you might be having directly, but they might point you in the right direction when trying to find and resolve performance issues with a WPF app. First off, performance is something you shouldn't try and improve without evidence, and this means having evidence proving you've improved the performance - before & after metrics for example. Without this you're basically pissing into the wind, which can be fun from a developer point of view but bad for a project :) So, what do I mean by ' Dispatcher thread performance '? The 'dispatcher thread' or the 'UI thread' is probably the most

Showing a message box from a ViewModel in MVVM

I was doing a code review with a client last week for a WPF app using MVVM and they asked ' How can I show a message from the ViewModel? '. What follows is how I would (and have) solved the problem in the past. When I hear the words ' show a message... ' I instantly think you mean show a transient modal message box that requires the user input before continuing ' with something else ' - once the user has interacted with the message box it will disappear. The following solution only applies to this scenario. The first solution is the easiest but is very wrong from a separation perspective. It violates the ideas behind the Model-View-Controller pattern because it places View concerns inside the ViewModel - the ViewModel now knows about the type of the View and specifically it knows how to show a message box window: The second approach addresses this concern by introducing the idea of messaging\events between the ViewModel and the View. In the example below

Implementing a busy indicator using a visual overlay in MVVM

This is a technique we use at work to lock the UI whilst some long running process is happening - preventing the user clicking on stuff whilst it's retrieving or rendering data. Now we could have done this by launching a child dialog window but that feels rather out of date and clumsy, we wanted a more modern pattern similar to the way <div> overlays are done on the web. Imagine we have the following simple WPF app and when 'Click' is pressed a busy waiting overlay is shown for the duration entered into the text box. What I'm interested in here is not the actual UI element of the busy indicator but how I go about getting this to show & hide from when using MVVM. The actual UI elements are the standard Busy Indicator coming from the WPF Toolkit : The XAML behind this window is very simple, the important part is the ViewHost. As you can see the ViewHost uses a ContentPresenter element which is bound to the view model, IMainViewModel, it contains 3 child v