Ativação de MSMQ

A amostra de MsmqActivation demonstra como hospedar aplicativos no WAS (Serviço de Ativação de Processo do Windows) que lê uma fila de mensagens. Esta amostra usa netMsmqBinding e se baseia na amostra de Comunicação Bidirecional. Nesse caso, o serviço é um aplicativo hospedado pela Web e o cliente é auto-hospedado e envia os resultados para o console para observar os status das ordens de compra enviadas.

Observação

O procedimento de instalação e as instruções de compilação dessa amostra estão no final deste tópico.

O WAS (Serviço de Ativação de Processo do Windows), o novo mecanismo de ativação de processo do Windows Server 2008, fornece recursos semelhantes a IIS que antes só estavam disponíveis para aplicativos baseados em HTTP que usam protocolos não HTTP. O WCF (Windows Communication Foundation) usa a interface do Adaptador do Ouvinte para comunicar solicitações de ativação recebidas por protocolos não HTTP compatíveis com o WCF, tais como TCP, Pipes Nomeados e MSMQ. A funcionalidade para receber solicitações em protocolos não HTTP é hospedada por serviços gerenciados do Windows em execução no SMSvcHost.exe.

O serviço Net.Msmq Listener Adapter (NetMsmqActivator) ativa aplicativos enfileirados com base em mensagens na fila.

O cliente envia ordens de compra para o serviço a partir do escopo de uma transação. O serviço recebe e processa as ordens em uma transação. Em seguida, o serviço envia um retorno sobre o status da ordem para o cliente. Para facilitar a comunicação bidirecional, o cliente e o serviço usam filas para enfileirar ordens de compra e status das ordens.

O contrato de serviço IOrderProcessor define as operações unidirecionais de serviço que funcionam com o enfileiramento. A operação de serviço usa o ponto de extremidade de resposta para enviar status de ordens ao cliente. O endereço do ponto de extremidade de resposta é o URI da fila usada para enviar o status da ordem de volta para o cliente. O aplicativo de processamento de ordens implementa esse contrato.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true)]
    void SubmitPurchaseOrder(PurchaseOrder po,
                                           string reportOrderStatusTo);
}

O contrato de resposta para o qual o status da ordem será enviado é especificado pelo cliente. O cliente implementa o contrato de status de ordens. O serviço usa o cliente gerado por esse contrato para enviar o status da ordem de volta para o cliente.

[ServiceContract]
public interface IOrderStatus
{
    [OperationContract(IsOneWay = true)]
    void OrderStatus(string poNumber, string status);
}

A operação de serviço processa a ordem de compra enviada. O OperationBehaviorAttribute é aplicado à operação de serviço para especificar a inscrição automática na transação usada para receber a mensagem da fila e a conclusão automática da transação após a conclusão da operação de serviço. A classe Orders encapsula a funcionalidade de processamento de ordens. Nesse caso, ela adiciona a ordem de compra a um dicionário. A transação na qual a operação de serviço se inscreveu está disponível para as operações na classe Orders.

A operação de serviço, além de processar a ordem de compra enviada, responde ao cliente sobre o status da ordem.

public class OrderProcessorService : IOrderProcessor
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po, string reportOrderStatusTo)
    {
        Orders.Add(po);
        Console.WriteLine("Processing {0} ", po);
        Console.WriteLine("Sending back order status information");
        NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding();
        msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;
        OrderStatusClient client = new OrderStatusClient(msmqCallbackBinding, new EndpointAddress(reportOrderStatusTo));
        // please note that the same transaction that is used to dequeue purchase order is used
        // to send back order status
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
        {
            client.OrderStatus(po.PONumber, po.Status);
            scope.Complete();
        }
    }
}

A associação de cliente a ser usada é especificada usando um arquivo de configuração.

O nome da fila MSMQ é especificado na seção appSettings do arquivo de configuração. O ponto de extremidade do serviço é definido na seção System.serviceModel do arquivo de configuração.

Observação

O nome da fila MSMQ e o endereço do ponto de extremidade usam convenções de endereçamento ligeiramente diferentes. O nome da fila MSMQ usa um ponto (.) para o computador local e separadores de barra invertida em seu caminho. O endereço de ponto de extremidade do WCF especifica um esquema net.msmq: usa "localhost" para o computador local e barras de encaminhamento em seu caminho. Para ler uma fila hospedada no computador remoto, substitua "." e "localhost" pelo nome do computador remoto.

Um arquivo .svc com o nome da classe é usado para hospedar o código do serviço em WAS.

O próprio arquivo Service.svc contém uma diretiva para criar o OrderProcessorService.

<%@ServiceHost language="c#" Debug="true" Service="Microsoft.ServiceModel.Samples.OrderProcessorService"%>

O arquivo Service.svc também contém uma diretiva de assembly para garantir o carregamento de System.Transactions.dll.

<%@Assembly name="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"%>

O cliente cria um escopo de transação. A comunicação com o serviço ocorre no escopo da transação, fazendo com que ela seja tratada como uma unidade atômica em que todas as mensagens são bem-sucedidas ou falham. A transação é confirmada chamando Complete no escopo da transação.

using (ServiceHost serviceHost = new ServiceHost(typeof(OrderStatusService)))
{
    // Open the ServiceHostBase to create listeners and start listening
    // for order status messages.
    serviceHost.Open();

    // Create a proxy with given client endpoint configuration
    OrderProcessorClient client = new OrderProcessorClient();

    // Create the purchase order
    PurchaseOrder po = new PurchaseOrder();
    po.CustomerId = "somecustomer.com";
    po.PONumber = Guid.NewGuid().ToString();

    PurchaseOrderLineItem lineItem1 = new PurchaseOrderLineItem();
    lineItem1.ProductId = "Blue Widget";
    lineItem1.Quantity = 54;
    lineItem1.UnitCost = 29.99F;

    PurchaseOrderLineItem lineItem2 = new PurchaseOrderLineItem();
    lineItem2.ProductId = "Red Widget";
    lineItem2.Quantity = 890;
    lineItem2.UnitCost = 45.89F;

    po.orderLineItems = new PurchaseOrderLineItem[2];
    po.orderLineItems[0] = lineItem1;
    po.orderLineItems[1] = lineItem2;

    //Create a transaction scope.
    using (TransactionScope scope = new
        TransactionScope(TransactionScopeOption.Required))
    {
        // Make a queued call to submit the purchase order
        client.SubmitPurchaseOrder(po,
       "net.msmq://localhost/private/ServiceModelSamplesOrder/OrderStatus");
        // Complete the transaction.
        scope.Complete();
    }

    //Closing the client gracefully closes the connection and cleans up
    //resources
    client.Close();

    Console.WriteLine();
    Console.WriteLine("Press <ENTER> to terminate client.");
    Console.ReadLine();

    // Close the ServiceHostBase to shutdown the service.
    serviceHost.Close();
    }

O código do cliente implementa o contrato IOrderStatus para receber o status da ordem de serviço. Nesse caso, ele imprime o status da ordem.

[ServiceBehavior]
public class OrderStatusService : IOrderStatus
{
    [OperationBehavior(TransactionAutoComplete = true,
                        TransactionScopeRequired = true)]
    public void OrderStatus(string poNumber, string status)
    {
        Console.WriteLine("Status of order {0}:{1} ",
                                         poNumber , status);
    }
}

A fila de status de ordens é criada no método Main. A configuração do cliente inclui a configuração do serviço de status de ordens para hospedar esse serviço, conforme mostrado na configuração da amostra a seguir.

<appSettings>
    <!-- use appSetting to configure MSMQ queue name -->
    <add key="targetQueueName" value=".\private$\ServiceModelSamples/service.svc" />
    <add key="responseQueueName" value=".\private$\ServiceModelSamples/OrderStatus" />
  </appSettings>

<system.serviceModel>

    <services>
      <service
         name="Microsoft.ServiceModel.Samples.OrderStatusService">
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamples/OrderStatus"
                  binding="netMsmqBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderStatus" />
      </service>
    </services>

    <client>
      <!-- Define NetMsmqEndpoint -->
      <endpoint name="OrderProcessorEndpoint"
                address="net.msmq://localhost/private/ServiceModelSamples/service.svc"
                binding="netMsmqBinding"
                contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
    </client>

  </system.serviceModel>

Quando você executa a amostra, as atividades de cliente e de serviço são exibidas nas janelas do console do cliente e do servidor. Você pode ver se o servidor recebeu mensagens do cliente. Pressione ENTER em cada janela de console para desligar o servidor e o cliente.

O cliente exibe as informações de status da ordem enviadas pelo servidor:

Press <ENTER> to terminate client.
Status of order 70cf9d63-3dfa-4e69-81c2-23aa4478ebed :Pending

Para configurar, compilar, e executar o exemplo

  1. Verifique se o IIS 7.0 está instalado, pois ele é necessário para ativação do WAS.

  2. Verifique se você executou as Amostras do Procedimento de Instalação Única para o Windows Communication Foundation. Além disso, você precisa instalar os componentes de ativação não HTTP do WCF:

    1. No menu Iniciar, selecione Painel de Controle.

    2. Selecione Programas e Recursos.

    3. Clique em Ativar ou desativar os recursos do Windows.

    4. Em Resumo dos Recursos, clique em Adicionar Recursos.

    5. Expanda o nó Microsoft .NET Framework 3.0 e marque o recurso de Ativação não HTTP do Windows Communication Foundation.

  3. Para compilar a edição C# ou do Visual Basic .NET da solução, siga as instruções descritas em Como compilar as amostras do Windows Communication Foundation.

  4. Ative o cliente executando client.exe em uma janela de comando. Isso cria a fila e envia uma mensagem a ela. Deixe o cliente em execução para ver o resultado do serviço lendo a mensagem

  5. O serviço de ativação MSMQ é executado como Serviço de Rede por padrão. Portanto, a fila usada para ativar o aplicativo deve ter permissões de recebimento e espiada para o Serviço de Rede. É possível adicioná-las usando o MMC de Enfileiramento de Mensagens:

    1. No menu Iniciar, clique em Executar, digite Compmgmt.msc e pressione ENTER.

    2. Em Serviços e Aplicativos, expanda o Enfileiramento de Mensagens.

    3. Clique em Filas Particulares.

    4. Clique com o botão direito do mouse na fila (servicemodelsamples/Service.svc) e escolha Propriedades.

    5. Na guia Segurança, clique em Adicionar e forneça permissões de recebimento e espiada para o Serviço de Rede.

  6. Configure o WAS (Serviço de Ativação de Processo do Windows) para permitir a ativação do MSMQ.

    Como conveniência, as etapas a seguir são implementadas no arquivo em lote AddNetPipeSiteBinding.cmd localizado no diretório de amostras.

    1. Para permitir ativação do net.msmq, o site padrão precisa primeiro ser associado ao protocolo net.msmq. Isso é possível usando o appcmd.exe instalado com o conjunto de ferramentas de gerenciamento do IIS 7.0. Em um prompt de comando com privilégios elevados (administrador), execute o comando a seguir.

      %windir%\system32\inetsrv\appcmd.exe set site "Default Web Site"
      -+bindings.[protocol='net.msmq',bindingInformation='localhost']
      

      Observação

      Esse comando tem apenas uma única linha de texto.

      Esse comando adiciona uma associação de site net.msmq ao site padrão.

    2. Embora todos os aplicativos em um site compartilhem uma associação net.msmq em comum, cada aplicativo pode habilitar individualmente o suporte ao net.msmq. Para habilitar net.msmq para o aplicativo /servicemodelsamples, execute o comando a seguir em um prompt de comando com privilégios elevados.

      %windir%\system32\inetsrv\appcmd.exe set app "Default Web Site/servicemodelsamples" /enabledProtocols:http,net.msmq
      

      Observação

      Esse comando tem apenas uma única linha de texto.

      Esse comando permite que o aplicativo /servicemodelsamples seja acessado usando http://localhost/servicemodelsamples e net.msmq://localhost/servicemodelsamples.

  7. Se você não tiver feito isso anteriormente, verifique se o serviço de ativação do MSMQ está habilitado. No menu Iniciar, clique em Executar e digite Services.msc. Pesquise a lista de serviços para o Adaptador do Ouvinte Net.Msmq. Clique com o botão direito do mouse e selecione Propriedades. Defina o Tipo de Inicialização como Automático, clique em Aplicar e no botão Iniciar. Esta etapa só deve ser feita uma vez antes do primeiro uso do serviço Adaptador do Ouvinte Net.Msmq.

  8. Para executar o exemplo em uma configuração em um único ou em vários computadores, siga as instruções em Como executar os exemplos do Windows Communication Foundation. Além disso, altere o código no cliente que envia a ordem de compra para refletir o nome do computador no URI da fila ao enviar o pedido de compra. Use o seguinte código:

    client.SubmitPurchaseOrder(po, "net.msmq://localhost/private/ServiceModelSamples/OrderStatus");
    
  9. Remova a associação do site net.msmq adicionada por esta amostra.

    Como conveniência, as etapas a seguir são implementadas no arquivo em lote RemoveNetPipeSiteBinding.cmd localizado no diretório de amostras:

    1. Para remover o net.msmq da lista de protocolos habilitados, execute o comando a seguir em um prompt de comando com privilégios elevados.

      %windir%\system32\inetsrv\appcmd.exe set app "Default Web Site/servicemodelsamples" /enabledProtocols:http
      

      Observação

      Esse comando tem apenas uma única linha de texto.

    2. Para remover a associação de site do net.msmq, execute o comando a seguir em um prompt de comando com privilégios elevados.

      %windir%\system32\inetsrv\appcmd.exe set site "Default Web Site" --bindings.[protocol='net.msmq',bindingInformation='localhost']
      

      Observação

      Esse comando tem apenas uma única linha de texto.

    Aviso

    A execução do arquivo em lote redefinirá o DefaultAppPool para ser executado usando o .NET Framework versão 2.0.

Por padrão, a segurança está habilitada com o transporte de associação netMsmqBinding. Duas propriedades, MsmqAuthenticationMode e MsmqProtectionLevel, determinam juntas o tipo de segurança de transporte. Por padrão, o modo de autenticação é definido como Windows e o nível de proteção é definido como Sign. Para que o MSMQ forneça o recurso de autenticação e assinatura, ele deve fazer parte de um domínio. Se você executar esta amostra em um computador que não faz parte de um domínio, receberá o seguinte erro: "O certificado de enfileiramento de mensagem interna do usuário não existe".

Para executar a amostra em um computador ingressado em um grupo de trabalho

  1. Se o computador não fizer parte de um domínio, desative a segurança do transporte definindo o modo de autenticação e o nível de proteção como nenhum, como mostrado na configuração de amostra a seguir.

    <bindings>
        <netMsmqBinding>
            <binding configurationName="TransactedBinding">
                <security mode="None"/>
            </binding>
        </netMsmqBinding>
    </bindings>
    
  2. Altere a configuração no servidor e no cliente antes de executar a amostra.

    Observação

    Definir security mode como None equivale a configurar a segurança de MsmqAuthenticationMode, MsmqProtectionLevel e Message como None.

  3. Para habilitar a ativação em um computador ingressado em um grupo de trabalho, o serviço de ativação e o processo de trabalho devem ser executados com uma conta de usuário específica (deve ser a mesma para ambos) e a fila deve ter ACLs para a conta de usuário específica.

    Para alterar a identidade sob a qual o processo de trabalho é executado:

    1. Execute Inetmgr.exe.

    2. Em Pools de Aplicativos, clique com o botão direito do mouse em AppPool (normalmente DefaultAppPool) e escolha Definir Padrões do Pool de Aplicativos....

    3. Altere as propriedades de Identidade para usar a conta de usuário específica.

    Para alterar a identidade com a qual o Serviço de Ativação é executado:

    1. Execute Services.msc.

    2. Clique com o botão direito do mouse no Adaptador Net.MsmqListener e escolha Propriedades.

  4. Altere a conta na guia LogOn.

  5. No grupo de trabalho, o serviço também deve ser executado usando um token irrestrito. Para isso, execute o seguinte em uma janela de comando:

    sc sidtype netmsmqactivator unrestricted
    

Confira também