Several people have asked for the source of the sample on Soma’s blog about Rx. The sample explains how to write a prototypical Silverlight-based AJAX application, the killer scenario for Rx, where you have to mash up events from the UI with asynchronous calls to several Web services. Specifically, the sample makes three concurrent calls to the Bing translation service and shows the first two results that come back.
To run the sample, just create a new Silverlight project. No need to add a Web site for it. Just the basic project with an automatically generated test page is sufficient.
Since I am a complete kludge when it comes to UI design, I do not even try to make it look fancy. Just a TextBox for the user input and three TextBlocks to show the results of the translations of the input into various languages. Here is the contents of my MainPage.xaml:
Any suggestions for more a more appealing UI design are very welcome.
The first step is to add a service reference to the Bing translation service. You will have to sign up for a Bing API key at http://msdn.microsoft.com/en-us/library/dd251056.aspx. When you have your key, add a service reference to http://api.bing.net/search.wsdl?AppID=[insert your own key here]&Version=2.2 using BingService for the namespace. In the advanced settings choose System.Array for the collection type and unselect “Reuse types in reference assemblies”. If this all works, you will have a BingService entry in your Service References folder in your project:
Once we have the service reference to Bing, we will expose the raw generated service as an async subject AsyncSubject<TranslationResponse> that we hook up to the SearchCompleted event of the SearchAsync call. Do not forget to insert your own Bing API key in the code below.
Before we return from the wrapper, we hide the IObserver aspect of the subject and make sure that we transition back to the Dispatcher thread to avoid the dreaded “not on the UI thread” exceptions.
All the real orchestration is done inside MainPage.xaml.cs. First we expose the KeyUp events of the TextBox _input as an observable collection of type IObservable<IEvent<KeyEventArgs>> using the IObservable.FromEvent helper, making sure that the subscription happens on the correct thread.
Since we do not want to invoke a search upon each keystroke, we throttle the input stream such that it only fires an event when the user has paused typing for ½ second. The simple LINQ query transforms the observable collection of KeyUp events into an observable collection of strings containing the Text of the input after each KeyUp event:
The core of the sample fires of three Bing searches let dutch = text.Translate("en", "nl"), …, for the word that the user has typed, and then uses a join pattern to wait for the first two of the three results to come back. You can think of join patterns as Outlook rules where instead of specifying what happens when a new email comes in, you specify rules for what happens when a new notification arrives on an observable collection. If the user types a new word before the results of the service call have arrived, we ignore the results using the TakeUntil(words) function.
Finally, we can subscribe to the observable collection of translations and update the UI with the translations provided by Bing:
While this is a much simplified example, it capture the essential design pattern of many AJAX applications where we need to react to UI events, orchestrate a number of concurrent webservice calls as the result of these UI events and update the UI with the results.
I've implemented it on my own with some modifications. The full sourcecode as SL3 Visual Studio solution, a live demo hosted on Azure and the description how to use the code can be found here: http://www.minddriven.de/?p=550 . Please don't forget to request an AppId for using the Bing Web Service API from http://www.bing.com/developers/createapp.aspx and to put it in the BingService.AppId field (BingService.cs) in my sources.
Thanks Eric and the Rx team for giving us this example.
it would be nice I you could describe how this implementation changes with the new IScheduler.
If I understand the video correctly we don't really want to do .ObserveOnDispatcher() and .SubscribeOnDispatcher() and the line with .Throttle() needs also a change.