Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Managing async service calls using Silverlight and Reactive Extensions

So I'm reading up on Rx and having a difficult time grokking it. I have a Silverlight app that needs to make say 6 calls to a specific service asynchronously. In the old days, we'd handle this by making the calls and querying the userState/token to match the response with the request since they're not guaranteed to return in the order we called them. However, I suspect Rx handles this in a far more elegant manner. But I can't get it to work. Here's what I have so far...

myCollection.Add(new myObject(1));
myCollection.Add(new myObject(2));
myCollection.Add(new myObject(3));
myCollection.Add(new myObject(4));
myCollection.Add(new myObject(5));
myCollection.Add(new myObject(6));

foreach (var myItem in myCollection)
{
    var myObservable = Observable.FromEventPattern<MyServiceMethodCompletedEventArgs>
    (
        f => myServiceClient.MyServiceMethodCompleted += f,
        f => myServiceClient.MyServiceMethodCompleted -= f
    ).Take(1).ObserveOn(SynchronizationContext.Current);

    myObservable.Subscribe
    (
    s =>
    {
        if (s.EventArgs.Error == null)
        {

        myItem.MyProperty = s.EventArgs.Result;
        }
    }
    );

    myServiceClient.MyServiceMethodAsync(myItem);
}

I hope you can see what I'm trying to achieve here...

What I end up with is all of myObject's being set to the result of the first call that returns.

I'm sure it's something silly but I haven't been able to figure it out yet.

Thanks :)

like image 534
Senkwe Avatar asked Oct 11 '22 11:10

Senkwe


1 Answers

Consider trying the Observable.FromAsyncPattern instead of Observable.FromEventPattern. There is a trick to using FromAsyncPattern in Silverlight (and the phone) because the BeginInvoke/EndInvoke pair are not exposed directly by the service proxy. However, if you use the interface for the service proxy rather than the service proxy itself, you can access the begin/end pattern:

IMyService svc = new myServiceClient();
var svcObservable = Observable.FromAsyncPattern<T, MyServiceResultArgs>
                        (svc.BeginMyServiceMethod, svc.EndMyServiceMethod);

Now, you can switch from using foreach (an anti-pattern with LINQ) to making your myCollection into an observable and SelectMany between the myCollection and the service request as follows:

var requestResult = from myItem in myCollection.ToObservable()
                    from result in svcObservable(myItem)
                    select new {myItem, result};

requestResult.Subscribe(result => result.myItem.myProperty = result.result);

One additional word of caution: If you use the FromAsyncPattern in silverlight this way, the result will come back on a background thread. You will need to take care teo delegate back to the dispatcher.

If you want to see this in action, check out the last 20 minutes or so of my Mix presentation at http://channel9.msdn.com/events/MIX/MIX11/EXT08.

like image 152
Jim Wooley Avatar answered Jan 01 '23 11:01

Jim Wooley