Использование Observable.FromEvent при вызове службы WCF в Silverlight

Я пытаюсь использовать .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

person LBushkin    schedule 23.12.2009    source источник


Ответы (1)


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

Оказывается, выбор потока для выполнения подписанного наблюдателя очень важен при работе с вызовами 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
person LBushkin    schedule 24.12.2009