Thursday Night

Paul Betts’s personal website / blog / what-have-you

Calling Web Services in Silverlight using ReactiveXaml

One of the scenarios that our summer intern Roberto Sonnino pointed out over the summer that was somewhat annoying in ReactiveXaml (my MVVM library that integrates the Reactive Extensions for .NET), was making RxXaml more friendly to asynchronous web service calls in Silverlight. Since this is a pretty important scenario, I decided to hack on it some (it’s always been possible, just not as easy).

Getting our function prototype correct

Remember from an earlier post that an IObservable can be used as a Future, a “box” that will eventually contain the result of a web service call or other asynchronous function, or the error information. So to this end, we’d really like our web service calls to all be vaguely of the form:

IObservable[Something] CoolWebServiceCall(object Param1, object Param2 /*etc*/);

However, we know that neither HttpWebRequest nor the web service generated code looks anything like that. Normal Silverlight objects use an OnCompleted event to fire a callback once the call completes. The Rx framework designers saw this coming however, and gave us a pretty handy function to deal with it: Observable.FromAsyncPattern(). This function will take a BeginXXXX/EndXXXX pair that follows the .NET Asynchronous Pattern and in return, will give us a Func that follows the form above, without us having to write some boilerplate code to connect the async method to an IObservable.

An example: looking at the Bing Translation API

One of the most simple public web services is the Bing Translation API, so its Translate() method is a good candidate for our example. The synchronous signature is:

string Client.Translate(string appId, string text, string fromLang, string toLang);

Here’s how we could take this and turn it into an Rx-friendly Async function – don’t be scared off by the five template parameters, they’re just the types of the parameters and return value, in the same order as a Func<T>:

var client = new LanguageServiceClient();
var translate_func = Observable.FromAsyncPattern[string,string,string,string,string]
    (client.BeginTranslate, client.EndTranslate);

IObservable[string] future = translate_func(appId, "Hello World!", "en", "de");
string result = future.First();   // This will *wait* until the call returns!!
>>> "Guten Tag, Welt!"

//
// Let’s try with an array…
//

var input = new[] {"one", "two", "three"};

// Fire off three asynchronous web service calls at the same time
var future_items = input.ToObservable()
    .SelectMany(x => translate_func(appId, x, "en", "fr"));

// This waits for *all* the web service calls to return
string[] result_array = future_items.ToArray()
>>> ["un", "deux", "trois"]

An important note for Silverlight!

Silverlight’s web service generated client code does something a bit annoying – it hides away the BeginXXXX/EndXXXX calls, presumably to make the Intellisense cleaner. However, they’re not gone, the way you can get them back is by casting the MyCoolServiceClient object to its underlying interface (i.e. the LanguageServiceClient object has a generated ILanguageServiceClient interface that it implements)

Turning this into a Command

Once we’ve got the function, turning it into a command is easy via a new method introduced to ReactiveAsyncCommandRegisterObservableAsyncFunction. This method is almost identical to RegisterAsyncFunction, but instead of expecting a synchronous Func which will be run on the TPL Task pool, it expects a Func that returns an IObservable as described above. Here’s a simple example of a good ViewModel object that demonstrates this:

public class TranslateViewModel : ReactiveObject
{
    //
    // Input text
    //

    string _TextToTranslate;
    public string TextToTranslate {
        get { return _TextToTranslate; }
        set { RaiseAndSetIfChanged(x => x.TextToTranslate, value); }
    }

    //
    // The "output" property we bind to in the UI
    //

    ObservableAsPropertyHelper[string] _TranslatedText;
    public string TranslatedText {
        get { return _TranslatedText.Value; }
    }

    public ReactiveAsyncCommand DoTranslate { get; protected set; }

    const string appId = "Get your own, buddy!";
    public TranslateViewModel()
    {
        var client = new LanguageServiceClient();
        var translate_func = Observable.FromAsyncPattern[string,string,string,string,string](
                client.BeginTranslate, client.EndTranslate);

        // Only one web call at a time please!
        DoTranslate = new ReactiveAsyncCommand(null, 1);

        //
        // ‘x’ is the CommandParameter passed in, which we will use as the
        // source text
        //

        var results = DoTranslate.RegisterObservableAsyncFunction(
            x => translate_func(appId, (string)x, "en", "de"));
           
        _TranslatedText = this.ObservableToProperty(
            results, x => x.TranslatedText);
    }
}

What does that get us?

Let’s review what this fairly short, readable code gets us – using a few simple bindings, we’ll have a fully non-blocking, responsive UI that correctly handles a lot of the edge cases associated with background operations: greying out the Button attached to the Command while the web call is running, saving off the results, then notifying the UI that there is something new to display so that it updates instantly, without any tricky callbacks or mutable state variables that have to be guarded by Lock statements to ensure multithreaded safety. That’s pretty cool.

Written by Paul Betts

September 26th, 2010 at 4:00 pm