Pergunta

Estou tentando usar a estrutura reativa .NET para simplificar algumas chamadas assíncronas para um serviço WCF usado por um aplicativo Silverlight 3 que estou escrevendo.

O problema é que estou tendo dificuldade em encontrar uma maneira de estruturar meu código de uma maneira que funcione. Parte do problema, sem dúvida, é entender quais mecanismos estão disponíveis em reativo e como usá -los para resolver meu problema.

Estou tentando reunir uma série de chamadas de servidor WCF - se fossem síncronas, eles se pareceriam algo assim:

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

As chamadas para m_Server.XXXX() Costumava ser implementado diretamente no aplicativo Silveright (portanto, eles poderiam ser síncronos) - mas agora são implementados em um serviço WCF. Desde que o Silverlight obriga você a ligar para os serviços da WCF de forma assíncrona - a reescrita deste bloco de código tem sido complicada.

Eu esperava usar Observable.FromEvent<>() Para se inscrever nos vários XXXCompleted Eventos que o código de proxy do WCF gera, mas não está claro para mim como fazer com que isso funcione. Minha tentativa original parecia algo como:

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
Foi útil?

Solução

Consegui descobrir como fazer isso funcionar. Estou postando esta resposta no interesse de compartilhar o que aprendi.

Acontece que decidir em qual thread executar um observador inscrito é muito importante ao lidar com as chamadas do WCF do Silverlight. No meu caso, eu precisava garantir que o código subscrito seja executado no tópico da interface do usuário - que foi realizado pela seguinte mudança:

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top