Padrões de Design: Publicar-Subscrever Baseado em Lista

O exemplo ListBasedPublishSubscribe ilustra o padrão Publish-Subscribe baseado em lista implementado como um programa WCF (Windows Communication Foundation).

Nota

O procedimento de configuração e as instruções de compilação para este exemplo estão localizados no final deste tópico.

O padrão de design Publish-Subscribe baseado em lista é descrito na publicação Microsoft Patterns & Practices, Integration Patterns. O padrão Publicar-Assinar passa informações para uma coleção de destinatários que se inscreveram em um tópico de informações. A publicação-subscrição baseada em listas mantém uma lista de subscritores. Quando há informações para compartilhar, uma cópia é enviada para cada assinante da lista. Este exemplo demonstra um padrão dinâmico de publicação-assinatura baseado em lista, onde os clientes podem se inscrever ou cancelar a assinatura com a frequência necessária.

O exemplo Publish-Subscribe baseado em lista consiste em um cliente, um serviço e um programa de fonte de dados. Pode haver mais de um cliente e mais de um programa de fonte de dados em execução. Os clientes subscrevem o serviço, recebem notificações e cancelam a subscrição. Os programas de fonte de dados enviam informações para o serviço para serem compartilhadas com todos os assinantes atuais.

Neste exemplo, o cliente e a fonte de dados são programas de console (arquivos .exe) e o serviço é uma biblioteca (.dll) hospedada no IIS (Serviços de Informações da Internet). A atividade do cliente e da fonte de dados é visível na área de trabalho.

O serviço usa comunicação duplex. O ISampleContract contrato de serviço é emparelhado com um contrato de retorno de ISampleClientCallback chamada. O serviço implementa operações de serviço de Assinatura e Cancelamento de Assinatura, que os clientes usam para ingressar ou sair da lista de assinantes. O serviço também implementa a PublishPriceChange operação de serviço, que o programa de fonte de dados chama para fornecer novas informações ao serviço. O programa cliente implementa a operação de PriceChange serviço, que o serviço chama para notificar todos os assinantes de uma alteração de preço.

// Create a service contract and define the service operations.
// NOTE: The service operations must be declared explicitly.
[ServiceContract(SessionMode=SessionMode.Required,
      CallbackContract=typeof(ISampleClientContract))]
public interface ISampleContract
{
    [OperationContract(IsOneWay = false, IsInitiating=true)]
    void Subscribe();
    [OperationContract(IsOneWay = false, IsTerminating=true)]
    void Unsubscribe();
    [OperationContract(IsOneWay = true)]
    void PublishPriceChange(string item, double price,
                                     double change);
}

public interface ISampleClientContract
{
    [OperationContract(IsOneWay = true)]
    void PriceChange(string item, double price, double change);
}

O serviço usa um evento .NET Framework como o mecanismo para informar todos os assinantes sobre novas informações. Quando um cliente ingressa no serviço chamando Subscribe, ele fornece um manipulador de eventos. Quando um cliente sai, ele cancela a inscrição de seu manipulador de eventos do evento. Quando uma fonte de dados chama o serviço para relatar uma alteração de preço, o serviço gera o evento. Isso chama cada instância do serviço, uma para cada cliente que se inscreveu, e faz com que seus manipuladores de eventos sejam executados. Cada manipulador de eventos passa as informações para seu cliente por meio de sua função de retorno de chamada.

public class PriceChangeEventArgs : EventArgs
    {
        public string Item;
        public double Price;
        public double Change;
    }

    // The Service implementation implements your service contract.
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
    public class SampleService : ISampleContract
    {
        public static event PriceChangeEventHandler PriceChangeEvent;
        public delegate void PriceChangeEventHandler(object sender, PriceChangeEventArgs e);

        ISampleClientContract callback = null;

        PriceChangeEventHandler priceChangeHandler = null;

        //Clients call this service operation to subscribe.
        //A price change event handler is registered for this client instance.

        public void Subscribe()
        {
            callback = OperationContext.Current.GetCallbackChannel<ISampleClientContract>();
            priceChangeHandler = new PriceChangeEventHandler(PriceChangeHandler);
            PriceChangeEvent += priceChangeHandler;
        }

        //Clients call this service operation to unsubscribe.
        //The previous price change event handler is unregistered.

        public void Unsubscribe()
        {
            PriceChangeEvent -= priceChangeHandler;
        }

        //Information source clients call this service operation to report a price change.
        //A price change event is raised. The price change event handlers for each subscriber will execute.

        public void PublishPriceChange(string item, double price, double change)
        {
            PriceChangeEventArgs e = new PriceChangeEventArgs();
            e.Item = item;
            e.Price = price;
            e.Change = change;
            PriceChangeEvent(this, e);
        }

        //This event handler runs when a PriceChange event is raised.
        //The client's PriceChange service operation is invoked to provide notification about the price change.

        public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
        {
            callback.PriceChange(e.Item, e.Price, e.Change);
        }

    }

Ao executar o exemplo, inicie vários clientes. Os clientes subscrevem o serviço. Em seguida, execute o programa de fonte de dados, que envia informações para o serviço. O serviço transmite a informação a todos os assinantes. Você pode ver a atividade em cada console do cliente confirmando que as informações foram recebidas. Pressione ENTER na janela do cliente para desligar o cliente.

Para configurar e compilar o exemplo

  1. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

Para executar a amostra na mesma máquina

  1. Teste se você pode acessar o serviço usando um navegador digitando o seguinte endereço: http://localhost/servicemodelsamples/service.svc. Uma página de confirmação deve ser exibida em resposta.

  2. Execute Client.exe de \client\bin\, sob a pasta específica do idioma. A atividade do cliente é exibida na janela do console do cliente. Lançar vários clientes.

  3. Execute Datasource.exe de \datasource\bin\, sob a pasta específica do idioma. A atividade da fonte de dados é exibida na janela do console. Uma vez que a fonte de dados envia informações para o serviço, elas devem ser passadas para cada cliente.

  4. Se o cliente, a fonte de dados e os programas de serviço não puderem se comunicar, consulte Dicas de solução de problemas para exemplos de WCF.

Para executar a amostra em máquinas

  1. Configure a máquina de serviço:

    1. Na máquina de serviço, crie um diretório virtual chamado ServiceModelSamples. O arquivo em lotes Setupvroot.bat do procedimento de instalação única para os exemplos do Windows Communication Foundation pode ser usado para criar o diretório de disco e o diretório virtual.

    2. Copie os arquivos de programa de serviço de %SystemDrive%\Inetpub\wwwroot\servicemodelsamples para o diretório virtual ServiceModelSamples na máquina de serviço. Certifique-se de incluir os arquivos no diretório \bin.

    3. Teste se você pode acessar o serviço da máquina cliente usando um navegador.

  2. Configure as máquinas cliente:

    1. Copie os arquivos de programa cliente da pasta \client\bin\, na pasta específica do idioma, para as máquinas cliente.

    2. Em cada arquivo de configuração do cliente, altere o valor de endereço da definição de ponto de extremidade para corresponder ao novo endereço do seu serviço. Substitua quaisquer referências a "localhost" por um nome de domínio totalmente qualificado no endereço.

  3. Configure a máquina da fonte de dados:

    1. Copie os arquivos de programa da fonte de dados da pasta \datasource\bin\, na pasta específica do idioma, para a máquina da fonte de dados.

    2. No arquivo de configuração da fonte de dados, altere o valor de endereço da definição de ponto de extremidade para corresponder ao novo endereço do seu serviço. Substitua quaisquer referências a "localhost" por um nome de domínio totalmente qualificado no endereço.

  4. Nas máquinas cliente, inicie Client.exe a partir de um prompt de comando.

  5. Na máquina da fonte de dados, inicie Datasource.exe a partir de um prompt de comando.