views:

986

answers:

1

I am trying to use the .NET Reactive Framework to simplify some asynchronous calls to a WCF service used by a Silverlight 3 app that I'm writing.

The trouble is that I'm having a hard time finding a way to structure my code in a way that will work. Part of the problem, no doubt, is understanding what mechanisms are available in Reactive and how to use them to solve my problem.

I'm trying to string together a series of WCF server calls - if they were synchronous, they would look something like this:

switch( CurrentVisualState )
{
    case GameVisualState.Welcome:
        m_gameState = m_Server.StartGame();
        if( m_GameState.Bankroll < Game.MinimumBet )
            NotifyPlayer( ... );  // some UI code here ...
        goto case GameVisualState.HandNotStarted;

    case GameVisualState.HandNotStarted:
    case GameVisualState.HandCompleted:
    case GameVisualState.HandSurrendered:
        UpdateUIMechanics();
        ChangeVisualState( GameVisualState.HandPlaceBet );
        break;

    case GameVisualState.HandPlaceBet:
        UpdateUIMechanics();
        // request updated game state from game server...
        m_GameState = m_Server.NextHand( m_GameState, CurrentBetAmount );
        if( CertainConditionInGameState( m_GameState ) )
            m_GameState = m_Server.CompleteHand( m_GameState );
        break;
}

The calls to m_Server.XXXX() used to be implemented directly within the Silveright app (thus they could be synchronous) - but now are implemented within a WCF service. Since Silverlight forces you to call WCF services asynchronously - rewriting this block of code has been tricky.

I was hoping to use Observable.FromEvent<>() to subscribe to the various XXXCompleted events that the WCF proxy code generates, but it's unclear to me how to get this to work. My original attempt looked something like:

var startObs = Observable.FromEvent<StartGameCompletedEventArgs>(
                  h => m_Server.StartGameCompleted += h,
                  h => m_Server.StartGameCompleted -= h );

startObs.Subscribe( e => { m_gameState = e.EventArgs.Result.StartGameResult;
                           if( m_GameState.Bankroll < Game.MinimumBet )
                               NotifyPlayer( ... );  // some UI code here ...
                           TransitionVisual( GameVisualState.HandNotStarted );
                         } );  // above code never reached...

m_Server.StartGameAsync();  // never returns, but the WCF service is called
+2  A: 

I was able to figure out how to get this to work. I am posting this answer in the interest of sharing what I've learned.

It turns out that deciding which thread to execute a subscribed observer on is very important when dealing with Silverlight WCF calls. In my case, I needed to ensure that the subscribed code runs on the UI thread - which was accomplished by the following change:

var startObs = Observable.FromEvent<StartGameCompletedEventArgs>(
                  h => m_Server.StartGameCompleted += h,
                  h => m_Server.StartGameCompleted -= h )
        .Take(1) // necessary to ensure the observable unsubscribes
        .ObserveOnDispatcher(); // controls which thread the observer runs on

startObs.Subscribe( e => { m_gameState = e.EventArgs.Result.StartGameResult;
                           if( m_GameState.Bankroll < Game.MinimumBet )
                               NotifyPlayer( ... );  // some UI code here ...
                           TransitionVisual( GameVisualState.HandNotStarted );
                         } );  // this code now executes with access to the UI

m_Server.StartGameAsync();  // initiates the call to the WCF service
LBushkin