Handling Asynchronous Interactions

0
258

For example, on the AppSettingsView page, a user can enable or disable push notifications of new surveys from the Microsoft Push Notification Service (MPNS). This requires the application to send a request to the MPNS that the application must handle asynchronously. The application displays a progress bar on the AppSettings- View page while it handles the asynchronous request.

Tailspin decided to use the Reactive Extensions (Rx) for .NET to run asynchronous tasks on the phone because it enables them to create compact, easy-to-understand code for complex asynchronous operations.

Using Reactive Extensions

Rx allows you to write compact, declarative code to manage complex, asynchronous operations. Rx can be described by comparing it to the more familiar concept of enumerable collections. Figure 3 shows two alternative approaches to iterating over a sequence.

Enumerable and observable sequences

To iterate over an enumerable sequence, you can use an iterator to pull each item from the sequence in turn, which is what the C# foreach construct does for you. With an observable sequence, you subscribe to an observable object that pushes items from the sequence to you. For example, you can treat the events raised by a control or the data arriving over the network as an observable sequence. Furthermore, you can use standard LINQ operators to filter the items from the observable sequence, and control which thread you use to process each item as it arrives.

For a description of Rx, see Appendix C, “Leveraging Device Capabilities.”

Inside the Implementation

The application performs an asynchronous request to the MPNS when the user changes his or her preference for push notifications on the AppSettingsView page. The following code example from the AppSettingsView. xaml file shows the definitions of the ToggleSwitch control that enables the user to set his or her preference and the progress bar that is active during the asynchronous request.

XAML

xmlns:toolkit=”clr-namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone.Controls.Toolkit”

<toolkit:ToggleSwitch Header=”Subscribe to Push Notifications”
Margin=”0,202,0,0″
IsChecked=”{Binding SubscribeToPushNotifications, Mode=TwoWay}” />

<ProgressBar Grid.Row=”2″
Height=”4″
Name=”progressBar”
VerticalAlignment=”Bottom”
HorizontalAlignment=”Stretch”
IsIndeterminate=”{Binding IsSyncing}” />

The ToggleSwitch control binds to the SubscribeToPush Notifications property of the AppSettingsViewModel, and the
ProgressBar control binds to the IsSyncing property of the App SettingsViewModel class.

The following code example from the AppSettingsViewModel class shows what happens when the user clicks the Save button on the AppSettingsView page. This Submit method handles the asynchronous call to the  UpdateReceiveNotifications method in the RegistrationServiceClient class by using Rx. Before it calls the
UpdateReceiveNotifications method, it first sets the IsSyncing property to true so that the UI can display an active progress meter.

The method handles the asynchronous call in three steps:

  1. The UpdateReceiveNotifications method in the Registration ServiceClient class returns an observable TaskSummary Result object that contains information about the task.
  2. The Submit method uses the ObserveOnDispatcher method to handle the TaskSummaryResult object on the dispatcher thread.
  3. The Subscribe method specifies how to handle the Task SummaryResult object and starts the execution of the
    source observable sequence by asking for the next item.

C#
public void Submit()
{
this.IsSyncing = true;
this.settingsStore.UserName = this.UserName;
this.settingsStore.Password = this.Password;
this.settingsStore.LocationServiceAllowed =
this.LocationServiceAllowed;
if (this.SubscribeToPushNotifications ==
this.settingsStore.SubscribeToPushNotifications)
{
this.IsSyncing = false;
this.NavigationService.GoBack();
return;
}
this.registrationServiceClient
.UpdateReceiveNotifications(
this.SubscribeToPushNotifications)
.ObserveOnDispatcher()
.Subscribe(
taskSummary =>
… ,
exception =>

);
}

The following code example shows the definition of the action that the Subscribe method performs when it receives a TaskSummary Result object. If the TaskSummaryResult object indicates that the change was successful, it updates the setting in local, isolated storage, sets the IsSyncing property to false, and navigates back to the previous view. If the TaskSummaryResult object indicates that the change failed, it reports the error to the user.

C#
taskSummary =>
{
if (taskSummary == TaskSummaryResult.Success)
{
this.settingsStore.SubscribeToPushNotifications =
this.SubscribeToPushNotifications;
this.IsSyncing = false;
this.NavigationService.GoBack();
}
else
{
var errorText = TaskCompletedSummaryStrings
.GetDescriptionForResult(taskSummary);
this.IsSyncing = false;
this.submitErrorInteractionRequest.Raise(
new Notification
{ Title = “Server error”, Content = errorText }, n => { });
}
}

The Subscribe method can also handle an exception returned from the asynchronous task. The following code example shows how it handles the scenario in the Tailspin mobile client where the asynchronous action throws a WebException exception.

C#
exception =>
{
if (exception is WebException)
{
var webException = exception as WebException;
var summary = ExceptionHandling.GetSummaryFromWebException(
“Update notifications”, webException);
var errorText = TaskCompletedSummaryStrings
.GetDescriptionForResult(summary.Result);
this.IsSyncing = false;
this.submitErrorInteractionRequest.Raise(
new Notification
{ Title = “Server error”, Content = errorText }, n => { });
}
else
{
throw exception;
}
}