Partilhar via


Tratamento de mensagens suspeitas no MSMQ 4.0

O exemplo MSMQ4 demonstra como executar o tratamento de mensagens suspeitas em um serviço. Este exemplo é baseado no exemplo de Vinculação MSMQ Transacionada . Este exemplo usa o netMsmqBinding. O serviço é um aplicativo de console auto-hospedado para permitir que você observe o serviço recebendo mensagens na fila.

Na comunicação em fila, o cliente se comunica com o serviço usando uma fila. Mais precisamente, o cliente envia mensagens para uma fila. O serviço recebe mensagens da fila. O serviço e o cliente, portanto, não precisam estar em execução ao mesmo tempo para se comunicar usando uma fila.

Uma mensagem suspeita é uma mensagem que é lida repetidamente de uma fila quando o serviço que lê a mensagem não pode processar a mensagem e, portanto, encerra a transação sob a qual a mensagem é lida. Nesses casos, a mensagem é repetida novamente. Teoricamente, isso pode durar para sempre se houver um problema com a mensagem. Isso só pode ocorrer quando você usa transações para ler da fila e invocar a operação de serviço.

Com base na versão do MSMQ, o NetMsmqBinding suporta deteção limitada à deteção completa de mensagens suspeitas. Depois que a mensagem foi detetada como envenenada, ela pode ser tratada de várias maneiras. Novamente, com base na versão do MSMQ, o NetMsmqBinding suporta manipulação limitada para manipulação total de mensagens suspeitas.

Este exemplo ilustra as instalações venenosas limitadas fornecidas na plataforma Windows Server 2003 e Windows XP e as instalações antiveneno completas fornecidas no Windows Vista. Em ambos os exemplos, o objetivo é mover a mensagem suspeita da fila para outra fila. Essa fila pode então ser atendida por um serviço de mensagens suspeitas.

Amostra de manipulação de veneno MSMQ v4.0

No Windows Vista, o MSMQ fornece um recurso de subfila suspeita que pode ser usado para armazenar mensagens suspeitas. Este exemplo demonstra a prática recomendada de lidar com mensagens suspeitas usando o Windows Vista.

A deteção de mensagens suspeitas no Windows Vista é sofisticada. Existem 3 propriedades que ajudam na deteção. O ReceiveRetryCount número de vezes que uma determinada mensagem é relida da fila e enviada para o aplicativo para processamento. Uma mensagem é relida da fila quando é colocada novamente na fila porque a mensagem não pode ser enviada para o aplicativo ou o aplicativo reverte a transação na operação de serviço. MaxRetryCycles é o número de vezes que a mensagem é movida para a fila de novas tentativas. Quando ReceiveRetryCount é atingida, a mensagem é movida para a fila de novas tentativas. A propriedade RetryCycleDelay é o atraso de tempo após o qual a mensagem é movida da fila de repetição de volta para a fila principal. O ReceiveRetryCount é redefinido para 0. A mensagem é tentada novamente. Se todas as tentativas de ler a mensagem falharam, então a mensagem é marcada como envenenada.

Uma vez que a mensagem é marcada como envenenada, a mensagem é tratada de acordo com as configurações na ReceiveErrorHandling enumeração. Para reiterar os valores possíveis:

  • Falha (padrão): Para culpar o ouvinte e também o host de serviço.

  • Soltar: para soltar a mensagem.

  • Mover: Para mover a mensagem para a subfila de mensagens suspeitas. Esse valor está disponível somente no Windows Vista.

  • Rejeitar: Para rejeitar a mensagem, envie-a de volta para a fila de mensagens mortas do remetente. Esse valor está disponível somente no Windows Vista.

O exemplo demonstra o uso da Move disposição para a mensagem venenosa. Move faz com que a mensagem seja movida para a subfila de veneno.

O contrato de serviço é IOrderProcessor, que define um serviço unidirecional adequado para uso com filas.

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

A operação de serviço exibe uma mensagem informando que está processando o pedido. Para demonstrar a funcionalidade de mensagem suspeita, a SubmitPurchaseOrder operação de serviço lança uma exceção para reverter a transação em uma invocação aleatória do serviço. Isso faz com que a mensagem seja colocada novamente na fila. Eventualmente, a mensagem é marcada como veneno. A configuração é definida para mover a mensagem suspeita para a subfila suspeita.

// Service class that implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
    static Random r = new Random(137);

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {

        int randomNumber = r.Next(10);

        if (randomNumber % 2 == 0)
        {
            Orders.Add(po);
            Console.WriteLine("Processing {0} ", po);
        }
        else
        {
            Console.WriteLine("Aborting transaction, cannot process purchase order: " + po.PONumber);
            Console.WriteLine();
            throw new Exception("Cannot process purchase order: " + po.PONumber);
        }
    }

    public static void OnServiceFaulted(object sender, EventArgs e)
    {
        Console.WriteLine("Service Faulted");
    }

    // Host the service within this EXE console application.
    public static void Main()
    {
        // Get MSMQ queue name from app settings in configuration.
        string queueName = ConfigurationManager.AppSettings["queueName"];

        // Create the transacted MSMQ queue if necessary.
        if (!System.Messaging.MessageQueue.Exists(queueName))
            System.Messaging.MessageQueue.Create(queueName, true);

        // Get the base address that is used to listen for WS-MetaDataExchange requests.
        // This is useful to generate a proxy for the client.
        string baseAddress = ConfigurationManager.AppSettings["baseAddress"];

        // Create a ServiceHost for the OrderProcessorService type.
        ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService), new Uri(baseAddress));

        // Hook on to the service host faulted events.
        serviceHost.Faulted += new EventHandler(OnServiceFaulted);

        // Open the ServiceHostBase to create listeners and start listening for messages.
        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        if(serviceHost.State != CommunicationState.Faulted) {
            serviceHost.Close();
        }

    }
}

A configuração do serviço inclui as seguintes propriedades de mensagem suspeita: receiveRetryCount, maxRetryCycles, retryCycleDelay, e receiveErrorHandling conforme mostrado no seguinte arquivo de configuração.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- Use appSetting to configure MSMQ queue name. -->
    <add key="queueName" value=".\private$\ServiceModelSamplesPoison" />
    <add key="baseAddress" value="http://localhost:8000/orderProcessor/poisonSample"/>
  </appSettings>
  <system.serviceModel>
    <services>
      <service
              name="Microsoft.ServiceModel.Samples.OrderProcessorService">
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison"
                  binding="netMsmqBinding"
                  bindingConfiguration="PoisonBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
      </service>
    </services>

    <bindings>
      <netMsmqBinding>
        <binding name="PoisonBinding"
                 receiveRetryCount="0"
                 maxRetryCycles="1"
                 retryCycleDelay="00:00:05"
                 receiveErrorHandling="Move">
        </binding>
      </netMsmqBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Processando mensagens da fila de mensagens suspeitas

O serviço de mensagens suspeitas lê mensagens da fila final de mensagens suspeitas e as processa.

As mensagens na fila de mensagens suspeitas são mensagens endereçadas ao serviço que está processando a mensagem, que pode ser diferente do ponto de extremidade do serviço de mensagens suspeitas. Portanto, quando o serviço de mensagens suspeitas lê mensagens da fila, a camada de canal WCF encontra a incompatibilidade nos pontos de extremidade e não envia a mensagem. Neste caso, a mensagem é endereçada ao serviço de processamento de pedidos, mas está sendo recebida pelo serviço de mensagens suspeitas. Para continuar a receber a mensagem, mesmo que a mensagem seja endereçada a um ponto de extremidade diferente, devemos adicionar um ServiceBehavior para filtrar endereços onde o critério de correspondência é corresponder a qualquer ponto de extremidade de serviço ao qual a mensagem é endereçada. Isso é necessário para processar com êxito as mensagens lidas da fila de mensagens suspeitas.

A implementação do serviço de mensagens suspeitas em si é muito semelhante à implementação do serviço. Implementa o contrato e processa as encomendas. O exemplo de código é o seguinte.

// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
public class OrderProcessorService : IOrderProcessor
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {
        Orders.Add(po);
        Console.WriteLine("Processing {0} ", po);
    }

    public static void OnServiceFaulted(object sender, EventArgs e)
    {
        Console.WriteLine("Service Faulted...exiting app");
        Environment.Exit(1);
    }

    // Host the service within this EXE console application.
    public static void Main()
    {

        // Create a ServiceHost for the OrderProcessorService type.
        ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService));

        // Hook on to the service host faulted events.
        serviceHost.Faulted += new EventHandler(OnServiceFaulted);

        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The poison message service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHostBase to shutdown the service.
        if(serviceHost.State != CommunicationState.Faulted)
        {
            serviceHost.Close();
        }
    }

Ao contrário do serviço de processamento de pedidos que lê mensagens da fila de pedidos, o serviço de mensagens suspeitas lê mensagens da subfila de pedidos suspeitos. A fila de veneno é uma subfila da fila principal, é chamada de "veneno" e é gerada automaticamente pelo MSMQ. Para acessá-lo, forneça o nome da fila principal seguido de um ";" e o nome da subfila, neste caso -"poison", conforme mostrado na configuração de exemplo a seguir.

Nota

No exemplo do MSMQ v3.0, o nome da fila suspeita não é uma subfila, mas sim a fila para a qual movemos a mensagem.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Microsoft.ServiceModel.Samples.OrderProcessorService">
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison;poison"
                  binding="netMsmqBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" >
        </endpoint>
      </service>
    </services>

  </system.serviceModel>
</configuration>

Quando você executa o exemplo, as atividades de cliente, serviço e serviço de mensagens suspeitas são exibidas nas janelas do console. Você pode ver o serviço receber mensagens do cliente. Pressione ENTER em cada janela do console para desligar os serviços.

O serviço começa a ser executado, processando ordens e, aleatoriamente, começa a encerrar o processamento. Se a mensagem indicar que processou o pedido, você pode executar o cliente novamente para enviar outra mensagem até ver que o serviço realmente encerrou uma mensagem. Com base nas configurações de veneno configuradas, a mensagem é tentada uma vez para processamento antes de movê-la para a fila de veneno final.

The service is ready.
Press <ENTER> to terminate service.

Processing Purchase Order: 0f063b71-93e0-42a1-aa3b-bca6c7a89546
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Processing Purchase Order: 5ef9a4fa-5a30-4175-b455-2fb1396095fa
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Aborting transaction, cannot process purchase order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89

Inicie o serviço de mensagens suspeitas para ler a mensagem envenenada da fila de venenos. Neste exemplo, o serviço de mensagens suspeitas lê a mensagem e a processa. Você pode ver que a ordem de compra que foi encerrada e envenenada é lida pelo serviço de mensagens venenosas.

The service is ready.
Press <ENTER> to terminate service.

Processing Purchase Order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Para configurar, compilar e executar o exemplo

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

  2. Se o serviço for executado primeiro, ele verificará se a fila está presente. Se a fila não estiver presente, o serviço criará uma. Você pode executar o serviço primeiro para criar a fila ou pode criar uma por meio do Gerenciador de Filas MSMQ. Siga estas etapas para criar uma fila no Windows 2008.

    1. Abra o Gerenciador do Servidor no Visual Studio 2012.

    2. Expanda a guia Recursos .

    3. Clique com o botão direito do mouse em Filas de Mensagens Privadas e selecione Nova, Fila Privada.

    4. Marque a caixa Transacional .

    5. Digite ServiceModelSamplesTransacted como o nome da nova fila.

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

  4. Para executar o exemplo em uma configuração de computador único ou cruzado, altere os nomes de fila para refletir o nome real do host em vez de localhost e siga as instruções em Executando os exemplos do Windows Communication Foundation.

Por padrão, com o transporte de ligação, a netMsmqBinding segurança está habilitada. Duas propriedades eMsmqProtectionLevel, juntas, MsmqAuthenticationMode determinam 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 este exemplo em um computador que não faz parte de um domínio, você receberá o seguinte erro: "O certificado interno de enfileiramento de mensagens do usuário não existe".

Para executar o exemplo em um computador associado a um grupo de trabalho

  1. Se o computador não fizer parte de um domínio, desative a segurança de transporte definindo o modo de autenticação e o nível de proteção como None mostrado na seguinte configuração de exemplo:

    <bindings>
        <netMsmqBinding>
            <binding name="TransactedBinding">
                <security mode="None"/>
            </binding>
        </netMsmqBinding>
    </bindings>
    

    Verifique se o ponto de extremidade está associado à associação definindo o atributo bindingConfiguration do ponto de extremidade.

  2. Certifique-se de alterar a configuração no PoisonMessageServer, no servidor e no cliente antes de executar o exemplo.

    Nota

    Definir security mode como None é equivalente a definir MsmqAuthenticationMode, MsmqProtectionLevele Message segurança para None.

  3. Para que o Meta Data Exchange funcione, registramos uma URL com vinculação http. Isso requer que o serviço seja executado em uma janela de comando elevada. Caso contrário, você terá uma exceção como: Unhandled Exception: System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8000/ServiceModelSamples/service/. Your process does not have access rights to this namespace (see https://go.microsoft.com/fwlink/?LinkId=70353 for details). ---> System.Net.HttpListenerException: Access is denied.