Использование Observable.FromEvent при вызове службы WCF в Silverlight - PullRequest
3 голосов
/ 23 декабря 2009

Я пытаюсь использовать .NET Reactive Framework, чтобы упростить некоторые асинхронные вызовы службы WCF, используемой приложением Silverlight 3, которое я пишу.

Беда в том, что мне трудно найти способ структурировать мой код так, чтобы он работал. Несомненно, частью проблемы является понимание того, какие механизмы доступны в Reactive и как их использовать для решения моей проблемы.

Я пытаюсь связать воедино серию вызовов сервера WCF - если бы они были синхронными, они бы выглядели примерно так:

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;
}

Вызовы m_Server.XXXX() раньше выполнялись непосредственно в приложении Silveright (таким образом, они могли быть синхронными), но теперь они реализованы в службе WCF. Поскольку Silverlight заставляет вас вызывать службы WCF асинхронно - переписать этот блок кода было сложно.

Я надеялся использовать Observable.FromEvent<>() для подписки на различные XXXCompleted события, которые генерирует прокси-код WCF, но мне неясно, как заставить это работать. Моя первоначальная попытка выглядела примерно так:

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

1 Ответ

3 голосов
/ 24 декабря 2009

Я смог понять, как заставить это работать. Я публикую этот ответ, чтобы поделиться тем, что я узнал.

Оказывается, что решение, в каком потоке выполнять подписанного наблюдателя, очень важно при работе с вызовами Silverlight WCF. В моем случае мне нужно было убедиться, что подписанный код выполняется в потоке пользовательского интерфейса - что было достигнуто следующим изменением:

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
...