Tuesday, 30 March 2010

Reactive Extensions, Silverlight and WCF

Here I will illustrate how Reactive Extensions (Rx) can be applied to asynchronous calls to a WCF web service in a Silverlight application.

We start with a simple customer database consisting of a single table of first and last names.

ID  First   Last

1   Fred    McFarlane
4   Susan   McFarlane
6   David   Green
10  Joe     Bloggs

Then we set up a WCF service to return a collection of customers. I used LINQ to SQL to generate the CustomersDemo DataContext instance.

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(
RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)
]
public class CustomersService
{
private string connection =
@"[My connection]";

[OperationContract]
public List<Customers> GetCustomers()
{
CustomersDemo db = new CustomersDemo(connection);
var customers = from customer in db.Customers
select customer;
return customers.ToList();
}
}

Asynchronous Access Without Rx


To consume the service in the Silverlight client…


Make the asynchronous call in the Page constructor.

public Page()
{
InitializeComponent();

CustomersServiceClient client =
new CustomersServiceClient();
client.GetCustomersCompleted +=
new EventHandler<GetCustomersCompletedEventArgs>(
client_GetCustomersCompleted
);
client.GetCustomersAsync();
}

Handle the completed event and display customers in a data grid.

void client_GetCustomersCompleted(
object sender,
GetCustomersCompletedEventArgs e
)
{
if (e.Error == null)
{
var customers = e.Result;
dg.ItemsSource = customers;
}
}

Results:


image


Asynchronous Access With Rx


In this case we dispense with the completed handler and centralise the code in the Page constructor. Instead of having a separate handler we create an IObservable from the GetCustomersCompleted event using the Observable.FromEvent method. The appended Take(1) is for returning a single value from the start of the observable sequence. It also implicitly unsubscribes the observer.

public Page()
{
InitializeComponent();

CustomersServiceClient client =
new CustomersServiceClient();
IObservable<IEvent<GetCustomersCompletedEventArgs>> observable =
Observable.FromEvent<GetCustomersCompletedEventArgs>(
client, "GetCustomersCompleted"
).Take(1);

observable.Subscribe(
e =>
{
if (e.EventArgs.Error == null)
{
var customers = e.EventArgs.Result;
dg.ItemsSource = customers;
}
});
client.GetCustomersAsync();
}
This produces the same results:

image

No comments:

Post a Comment