MOBILE

Windows Phone 7 Development : Handling Multiple Concurrent Requests with Rx.NET

5/5/2011 3:54:10 PM
So far, the weather application that you have created is sending as many requests for weather data as the user types in zip codes. When the data comes back from the weather web service, the order that this data comes back in is not guaranteed. For example, if the user first types in "32207" (Jacksonville) and then types in "10001" (New York City), the weather results for Jacksonville may come in behind New York City, yet the user would not realize that she's seeing Jacksonville's weather when New York's zip code still remains on the screen. It would be great if there were a solution that gave an application the power to cancel out all weather requests that occurred prior to the latest one, i.e., in our example, a request for Jacksonville weather is canceled as soon as request for New York City weather is made.

Rx.NET provides such a solution. There are two operators in Rx.NET—TakeUntil() and Switch—that allow for cancellation of operations that occur prior to the latest operation and are still "in-flight" so to speak, or are still pending the return values. Through the use of an elegant LINQ query, these operators tie together Observable collections, as you will see shortly. But first, there is some bad news: in the current implementation of .NET framework on Windows Phone 7, it is impossible to link the beginning of the asynchronous web service invocation to the end of that invocation. The root of the problem is the exclusion of the CreateChannel method implementation in the Windows Communication Foundation libraries on Windows Phone 7. Microsoft had to slim down and optimize .NET framework on the phone, and the loss of this method for the time being seems to be due to those optimization efforts.

Nevertheless, the technique for canceling "in-flight" requests still applies to the clients with full.NET framework installed (Windows Forms and WPF applications) and to the Silverlight platform. For the weather application, we will demonstrate the technique of canceling those requests by creating a new Observable collection for the weather service each time a user types in a new zip code. Note, however, that the Observable subscriptions that you will be creating listen for any completed weather service requests, and not the specific ones. In other words, each one of these subscriptions would process both Jacksonville and New York City weather from the example, and the order that this weather data comes in would be irrelevant. This is due to the limitation that we have discussed in the current implementation of Windows Phone 7 framework—at present, you cannot link the beginning of the web service call to the end of that service call on this platform.

To make the cancellation of operations on the Observable collections possible while those operations are "in-flight," you will change the code around to expose Observable collections to LINQ queries.

Follow these steps to make operation cancellation possible:

  1. At the top of the MainPage class (right above the constructor), paste the following code to declare a module-level Observable collection for the KeyUp events of the zip code text box:

    IObservable<IEvent<KeyEventArgs>> _keys;

  2. Expose the Observables for both the KeyUp event of the zip code text box and for the web service callback by adding the following two methods to your code:

    private IObservable<IEvent<GetWeatherByZipCodeCompletedEventArgs>> GetWeatherSubject()
    {
    return Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>(weatherClient, "GetWeatherByZipCodeCompleted");
    }

    private void GetKeys()
    {
    if (_keys == null)
    {
    _keys = Observable.FromEvent<KeyEventArgs>(txtZipCode, "KeyUp").Throttle(TimeSpan.FromSeconds(1)).DistinctUntilChanged();
    }
    }


The magic that makes the cancellations work appears in the next code snippet. Pay particularly close attention to the LINQ query; it establishes the relationship between the Observable collection for the KeyUp events and the Observable collection for the web service callbacks. Note that had Windows Phone 7 framework supported what is referred to as the Asynchronous pattern for web service calls (with the use of BeginXXX/EndXXX methods), you could have established a direct relationship between key sequences and web service invocations. However, with the following code, you have only a loose or indirect relationship between those two, since each subscriptionlistens for any and all responses from the weather web service, and not just for specific ones. Right after the LINQ statement, there is a Switch() operator that instructs the application to dispose of the old subscription to the weather web service once there is a new key sequence awaiting in the _keys Observable collection.

  1. Add the following code to the application:

    private void WireUpWeatherEvents()
    {
    GetKeys();
    var latestWeather = (from term in _keys
    select GetWeatherSubject()
    .Finally(() =>
    {
    Deployment.Current.Dispatcher.BeginInvoke(() => Debug.WriteLine("Disposed of prior subscription"));
    })
    ).Switch();

    latestWeather.ObserveOnDispatcher()
    .Subscribe(evt =>
    {
    if (evt.EventArgs.Result != null)
    {
    lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " + evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + " - " + evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();
    lblCelsius.Text = "Current Weather, Celsius: " + evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + " - " + evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();



    imgWeather.Source = new BitmapImage(new
    Uri(evt.EventArgs.Result.Details[0].WeatherImage, UriKind.Absolute));
    }
    },
    ex => {
    Deployment.Current.Dispatcher.BeginInvoke(() =>lblStatus.Text =
    ex.Message);
    }
    );
    }


Notice the .Finally statement in the code. Its purpose is to print a "Disposed of prior subscription" message into the Output windows when one Observable collection is being removed and replaced with the newer one. That occurs when there is a new event in the _keys module-level Observable collection.

Finally, you need to make some minor changes to the WireUpKeyEvents function, namely, the Observable sequence generation for the KeyUp event on the zip code has been moved into a separate GetKeys method.

  1. Replace the WiredUpKeyEvents() function with the following code:

    private void WireUpKeyEvents()
    {
    GetKeys();
    _keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
    {
    if (txtZipCode.Text.Length >= 5)
    {
    weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
    }
    });
    }


You are now ready to run the application.

  1. Press F5 and observe that the application behavior is virtually unchanged from the previous walkthroughs: you still type in the zip code and receive weather information for that zip code. However, behind the scenes, you will notice the messages printed in the Output window indicating that there are Observable sequences being disposed of in accordance to the new data (zip codes typed in) available in the key sequence observable collection.

Perhaps in the very near future, you will see a CreateChannel method available on the Windows Phone 7 platform. Once that happens, you could very easily enhance the foregoing walkthrough with the code linking the beginning and end of an asynchronous web service call through the Observable.FromAsyncPattern method. For right now, however, you can still take advantage of this extremely powerful feature of Rx.NET in Silverlight or on clients running the full version of .NET framework.

Other  
  •  WAP and Mobile HTML Security : Application Attacks on Mobile HTML Sites
  •  WAP and Mobile HTML Security : Authentication on WAP/Mobile HTML Sites & Encryption
  •  iPhone Application Development : Displaying and Navigating Data Using Table Views - Building a Simple Table View Application
  •  iPhone Application Development : Understanding Table Views and Navigation Controllers
  •  Windows Phone 7 Development : Revising WeatherRx to Manage Slow Data Connections
  •  Windows Phone 7 Development : Handling Data Connection Issues with Rx.NET
  •  Windows Phone 7 Development : Handling Errors in Rx.NET
  •  Windows Phone 7 Development : Using Rx.NET with Web Services to Asynchronously Retrieve Weather Data
  •  Windows Phone 7 Development : Media - Adding Sounds to an Application
  •  iPhone Application Development : Building a Multi-View Tab Bar Application (part 4) - Implementing the Summary View
  •  iPhone Application Development : Building a Multi-View Tab Bar Application (part 3) - Implementing the Volume View
  •  iPhone Application Development : Building a Multi-View Tab Bar Application (part 2) - Implementing the Area View
  •  iPhone Application Development : Building a Multi-View Tab Bar Application (part 1)
  •  Windows Phone 7 Development : Working with Video (part 2) - Coding the Application
  •  Windows Phone 7 Development : Working with Video (part 1)
  •  Windows Phone 7 Development : Plotting an Address on a Bing Maps Map and Working with the Bing Maps Service
  •  Windows Phone 7 Development : Using GeoCoordinateWatcher and the Bing Maps Control to Track Your Movements
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 3) - Adding Toolbar Controls
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 2) - Instantiating the View Controllers
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 1)
  •  
    Video
    Top 10
    The Micro Revolution
    Programming WCF : Queued Services - Queued Calls
    OTL – a new direction of electric tube amplifier
    Ipad Lion (Part 3) - Other possible features
    Gaming Laptop Recommendations (Part 2) - Intel HD Graphics, NVIDIA Geforce 6xxm Series, The Radeon HD 7xxxm Series
    Magix Music Maker MX
    Installing Remote Data Connectivity
    Wall Street’s “Technology Bubble” 2.0
    Database Availability Group Replication in Exchange Server 2010 : Comparing and Contrasting DAG Versus CCR/SCR/SCC
    Linux Software : Mint Debian
    Most View
    The Android Army invades! (Part 3) : Disaster recovery
    Symmetric Encryption
    Microsoft ASP.NET 4 : Profiles - Understanding Profiles
    Refrigerator Is Calling (Part 1)
    Collaborating via Blogs and Wikis : Evaluating Wikis for Collaboration
    Windows System Programming : Example: Listing File Attributes & Setting File Times
    Exploring the T-SQL Enhancements in SQL Server 2005 : The WAITFOR Command
    Windows Vista : Administering Workstations - Performing Remote PC Administration
    Design and Deploy High Availability for Exchange 2007 : Create Bookmark Create Note or Tag Implement Standby Continuous Replication (SCR)
    IIS 7.0 : Editing Configuration - Setting Configuration
    Anatomy of Utrabooks (Part 6) - Samsung Series 9 900X3A & Toshiba Portégé Z830
    Exploring the T-SQL Enhancements in SQL Server 2005 : TOP Enhancements
    Programming with DirectX : Shading and Surfaces - Types of Textures
    Major Access Control List Changes in Vista
    MSI Wind U180 - The Cedar Wind
    Algorithms for Compiler Design: WHY LR PARSING IS ATTRACTIVE
    Photo Rescuse
    Using Windows Phone 7 Technologies : Retrieving Accelerometer Data (part 2)
    iPhone 3D Programming : Blending and Augmented Reality - Wrangle Premultiplied Alpha
    Windows 7 : Troubleshooting Problems with Windows Media Center