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

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

Custom AuthorizationHandler for SignalR Hubs

How to implement IAuthorizationRequirement for SignalR in Asp.Net Core v5.0 Been battling this for a couple of days, and eventually ended up raising an issue on Asp.Net Core gitHub  to find the answer. Wanting to do some custom authorization on a SignalR Hub when the client makes a connection (Hub is created) and when an endpoint (Hub method) is called:  I was assuming I could use the same Policy for both class & method attributes, but it ain't so - not because you can't, because you need the signatures to be different. Method implementation has a resource type of HubInnovationContext: I assumed class implementation would have a resource type of HubConnectionContext - client connects etc... This isn't the case, it's infact of type DefaultHttpContext . For me I don't even need that, it can be removed completely  from the inheritence signature and override implementation. Only other thing to note, and this could be a biggy, is the ordering of the statements in th