MOBILE

Windows Phone 7 Development : Using Rx.NET with Web Services to Asynchronously Retrieve Weather Data

4/23/2011 3:53:32 PM
In this section, you will use a publicly available weather web service located at www.webservicex.net/WCF/Default.aspx to retrieve and display current weather for a given zip code within the United States. In addition to weather services, there are many other useful web services available at this location, including zip code validation and currency conversion. As an exercise in the usage of Rx.NET, you are encouraged to build useful, functional applications that take advantage of these services.

From the development point of view, the weather application will consist of (1) asynchronously capturing user input—zip code, and (2) asynchronously calling the web service and then displaying the current weather for a given zip code. Let's go ahead and create the application.

1. Creating a Windows Phone Project

First, you will create a new project, import all of the libraries and create service references necessary to make the weather application work.

  1. Launch Visual Studio 2010 Express for Windows Phone and create a new Windows Phone Application project. Name it "WeatherRx."

  2. In MainPage.xaml, change the name of the application to "WeatherRx" and change the page title to "Weather App" (you are also certainly welcome to name the application and the page according to your preference).

  3. Since you will be using Rx.NET to build this application, add a reference (by right-clicking and selecting Add Reference) to Microsoft.Phone.Reactive and System.Observable assemblies.

You need to add a Service Reference to the weather service already mentioned. The weather service is an .asmx web service hosted at www.webservicex.net.

  1. To add a reference to this service, right-click the Project Name and select Add Service Reference. In the dialog that comes up, enter the following value in the Address Textbox: http://www.webservicex.net/WeatherForecast.asmx. Press the "Go" button.

  2. The WeatherForecast service should appear on the left. Click the arrow next to it, make sure to select WeatherForecastSoap service, and then rename the namespace to "svcWeather."

  3. Your final Add Service screen should look like Figure 1.

  4. Press the OK button.

    Figure 1. Adding a Service Reference to the weather web service

2. Creating a User Interface

For the application, your goal is to create a screen that looks like the one shown in Figure 2. To assist in that objective, the XAML for visual elements that appear after the page title is pasted here.

  1. Open MainPage.xaml and add the following code:

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentGrid" Grid.Row="1">
    <TextBox Height="72" HorizontalAlignment="Left" Margin="0,51,0,0"
    Name="txtZipCode" Text="" VerticalAlignment="Top" Width="480" />
    <TextBlock Height="53" HorizontalAlignment="Left" Margin="6,13,0,0"
    Name="lblLegend" Text="Enter Zip Code Below for Current Weather" VerticalAlignment="Top"
    Width="462" />
    <TextBlock Height="30" HorizontalAlignment="Left" Margin="6,129,0,0"


    Name="lblWeatherFahrenheit" Text="Current Weather, Fahrenheit " VerticalAlignment="Top"
    Width="435" />
    <Image Height="150" HorizontalAlignment="Left" Margin="241,213,0,0"
    Name="imgWeather" Stretch="Fill" VerticalAlignment="Top" Width="200" />
    <TextBlock Height="30" HorizontalAlignment="Left" Margin="6,162,0,0"
    Name="lblCelsius" Text="Current Weather, Celsius" VerticalAlignment="Top" Width="435" />
    <TextBlock Height="30" Margin="6,379,39,0" Name="lblStatus" Text="" VerticalAlignment="Top" />
    </Grid>
    </Grid>


Notice that in addition to the textblocks that will hold the current weather information, the XAML also creates an image control that will show a visual representation of the current weather (e.g., sunny, raining, snowing, etc.). Notice also that the last </Grid>statement closes the LayoutGrid element, not shown in the preceding fragment.

Figure 2. WeatherRx design layout

3. Adding Logic to Get Weather Information

With design elements and proper references in place, you are ready to add code to the application. In this walkthrough, you will split the code into multiple functions for enhanced readability.

  1. Open MainPage.xaml.cs (by clicking MainPage.xaml and selecting View Code) and add the following using statements to the top of the page:

    using Microsoft.Phone.Reactive;
    using System.Windows.Media.Imaging;

  2. Add the following code after the InitializeComponent() statement of the MainPage() constructor:

    WireUpWeatherEvents();
    WireUpKeyEvents();

  1. Create the WireUpWeatherEvents function and its supporting GetWeatherSubject function by pasting the following code. Note how you have created a separate function (GetWeatherSubject) to return an Observable collection from the weather web service event.

    private void WireUpWeatherEvents()
    {
    var weather = GetWeatherSubject();
    weather.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
    {

    if (evt.EventArgs.Result.Details != 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 => { lblStatus.Text = "Sorry, we encountered a problem: " + ex.Message; }
    );
    }

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


  2. Create the WireUpKeyEvents function that will create an Observable collection from the KeyUp events and create subscription to that collection by adding the following code:

    private void WireUpKeyEvents()
    {
    var keys = Observable.FromEvent<KeyEventArgs>(txtZipCode,
    "KeyUp").Throttle(TimeSpan.FromSeconds(1)).DistinctUntilChanged();
    keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
    {
    if (txtZipCode.Text.Length >= 5)
    {
    weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
    }
    });

    }


  3. Press F5 to run the application. You should see a screen prompting you to enter the US zip code to retrieve the current weather for. If you enter your zip code, you should get a reasonable estimate of your current weather, both on the Fahrenheit and Celsius scales. You should also see a small picture with a visual representation of the current weather conditions. Figure 4 shows sample output for the Jacksonville, FL area (zip code of "32202").

Let's spend some more time dissecting the tools you used to build this application. First, you used Rx.NET to create an Observable collection from the asynchronous responses to the weather web service calls. You used the following statement to create that collection:

var weather =
Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>(weatherClient,
"GetWeatherByZipCodeCompleted");


You then defined an Observer for this data source, so that when the data is pushed from the web service to Observers, you take action by displaying that data in the User Interface.

Next, you created an Observable collection of the KeyUp events in the txtZipCode text box and created an Observer for that collection. As a result, whenever users pause their typing for one second, the Observer on the keys data source will validate whether five or more digits have been entered in the Zip Code field. Then, it goes ahead and calls the function GetWeatherByZipCodeAsync, which in turn invokes an asynchronous request to the weather web service.

It's important to note the asynchronous nature of all these calls—if you had other functionality built into the application, you could continue using it while the asynchronous request completes. The asynchronous processing is an area that Rx.NET was specifically designed to address.

If you have done some form of asynchronous programming prior to Rx.NET, you can certainly appreciate that foregoing single code line. Prior to Rx.NET, in an asynchronous method design pattern in .NET, two methods were provided. The first method started the computation, and the second method acquired the results of the computation. If there was more than one asynchronous operation, even just the simple ones we have illustrated in the weather example, the management of those multiple methods quickly became a headache. The fact that Rx.NET also attempts to parallelize asynchronous requests across all available cores is a hefty bonus to an already generous benefits package of clarity and powerful querying of Observers.

Figure 4. Sample output of WeatherRx application for zip code 32202

Other  
  •  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)
  •  Windows Phone 7 Development : Using Location Services - Simulating the Location Service
  •  Introducing the Windows Phone Location Service and Mapping APIs
  •  iPhone Application Development : Implementing a Custom Picker View (part 4) - Tweaking the Picker UI
  •  iPhone Application Development : Implementing a Custom Picker View (part 3) - Reacting to a Picker View Choice
  •  iPhone Application Development : Implementing a Custom Picker View (part 2)
  •  iPhone Application Development : Implementing a Custom Picker View (part 1)
  •  Windows Phone 7 Development : Isolated Storage - Working with Isolated Storage Settings
  •  Mobile Application Security : WebOS Security - Permissions and User Controls
  •  
    Top 10
    Active Directory Lightweight Directory Service (LDS)
    Configuring Windows 7 NIC Devices (part 1) - Configuring a Network Adapter & Troubleshooting a Network Adapter
    Programming the Mobile Web : Widgets and Offline Webapps - Standards
    Application Security in Windows Vista
    Reporting Services with SQL Azure : Starting a SQL Azure–Based Report
    Mouse Events in Silverlight
    Microsoft XNA Game Studio 3.0 : Displaying Images - Resources and Content (part 1)
    Windows 7 : Networking with TCP/IP (part 1) - Understanding IPv4 & Using Private IPv4 Addresses and Networking Protocols
    IIS 7.0 : Editing Configuration - Understanding Configuration Errors
    Transact-SQL in SQL Server 2008 : MERGE Statement
    Most View
    SQL Server 2008 : Explaining Advanced Query Techniques - Managing Internationalization Considerations
    SQL Server 2008 : Creating SQL Server Audits Using the GUI
    Mobile Application Security: The Apple iPhone - Development
    Transact-SQL in SQL Server 2008 : Insert over DML
    Windows 7 : Scheduling Maintenance Tasks
    Windows 7 : Protecting Your Computer While Browsing (part 4) - Restricting Permissions Using Security Zones
    Sharepoint 2007: Personal Sites and Personal Details (Available Only in MOSS)
    IIS 7.0 : Managing Configuration - Delegating Configuration (part 1)
    Business Intelligence in SharePoint 2010 with Business Connectivity Services : Consuming External Content Types (part 1) - External Lists & External Data
    Buffer Restrictions
    Getting the Most Out of the Microsoft Outlook Client : Security Enhancements in Outlook 2007
    SharePoint 2010 : PerformancePoint Services (part 2) - Using PerformancePoint
    Microsoft Content Management Server Development : Managing Channels and Postings with the PAPI - Moving Postings
    Programming Excel with VBA and .NET : Variables (part 3) - Constants, Enumerations & Arrays
    Architecting Applications for the Enterprise : UML Diagrams (part 1) - Use-Case Diagrams
    Deploying the Client for Microsoft Exchange Server 2010 : Understanding Deployment Options
    Beginning Android 3 : Working with Containers - Tabula Rasa
    WCF Services : Enumerations
    SharePoint 2010 : PerformancePoint Services (part 1) - PerformancePoint Central Administration Settings
    IUSR and IIS_USRS