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
Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.
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.
Abra o Gerenciador do Servidor no Visual Studio 2012.
Expanda a guia Recursos .
Clique com o botão direito do mouse em Filas de Mensagens Privadas e selecione Nova, Fila Privada.
Marque a caixa Transacional .
Digite
ServiceModelSamplesTransacted
como o nome da nova fila.
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 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
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.
Certifique-se de alterar a configuração no PoisonMessageServer, no servidor e no cliente antes de executar o exemplo.
Nota
Definir
security mode
comoNone
é equivalente a definirMsmqAuthenticationMode
,MsmqProtectionLevel
eMessage
segurança paraNone
.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
.