Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O exemplo DeadLetter demonstra como manipular e processar mensagens que falharam na entrega. É baseado no exemplo de Ligação MSMQ Transacionada. Este exemplo usa a netMsmqBinding vinculação. O serviço é um aplicativo de console auto-hospedado para permitir que você observe o serviço recebendo mensagens na fila.
Observação
O procedimento de configuração e as instruções de compilação para este exemplo estão localizados no final deste tópico.
Observação
Este exemplo demonstra a fila de mensagens mortas de cada aplicação que está disponível apenas no Windows Vista. O exemplo pode ser modificado para usar as filas padrão em todo o sistema para MSMQ 3.0 no Windows Server 2003 e Windows XP.
Na comunicação em fila, o cliente comunica-se com o serviço mediante 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 simultaneamente para se comunicarem usando uma fila.
Como a comunicação em fila pode envolver uma certa quantidade de inatividade, convém associar um valor de tempo de vida à mensagem para garantir que, caso tenha ultrapassado o tempo, a mensagem não seja entregue à aplicação. Há também casos em que um aplicativo deve ser informado se uma mensagem falhou na entrega. Em todos esses casos, como quando o tempo de vida da mensagem expirou ou a mensagem falhou na entrega, a mensagem é colocada em uma fila de letra morta. O aplicativo de envio pode então ler as mensagens na fila de mensagens mortas e tomar ações corretivas que variam de nenhuma ação para corrigir os motivos da falha na entrega e reenviar a mensagem.
A fila de letras mortas na NetMsmqBinding associação é expressa nas seguintes propriedades:
DeadLetterQueue propriedade para expressar o tipo de fila de mensagens mortas exigido pelo cliente. Esta enumeração tem os seguintes valores:
None: Nenhuma fila de mensagens mortas é exigida pelo cliente.System: A fila de mensagens mortas do sistema é usada para armazenar mensagens inativas. A fila de mensagens mortas do sistema é compartilhada por todos os aplicativos em execução no computador.Custom: Uma fila de letras mortas personalizada especificada usando a CustomDeadLetterQueue propriedade é usada para armazenar mensagens mortas. Esta funcionalidade só está disponível no Windows Vista. Isso é usado quando a aplicação deve utilizar a sua própria fila de mensagens mortas em vez de a partilhar com outras aplicações em execução no mesmo computador.CustomDeadLetterQueue para expressar a fila específica a ser usada como uma fila de letras mortas. Isso está disponível apenas no Windows Vista.
Neste exemplo, o cliente envia um lote de mensagens para o serviço de dentro do escopo de uma transação e especifica um valor arbitrariamente baixo para "time-to-live" para essas mensagens (cerca de 2 segundos). O cliente também especifica uma fila de mensagens mortas personalizada a ser usada para enfileirar as mensagens que expiraram.
O aplicativo cliente pode ler as mensagens na fila de mensagens mortas e tentar enviar novamente a mensagem ou corrigir o erro que fez com que a mensagem original fosse colocada na fila de mensagens mortas e enviasse a mensagem. No exemplo, o cliente exibe uma mensagem de erro.
O contrato de serviço é IOrderProcessor, conforme mostrado no código de exemplo a seguir.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
O código de serviço no exemplo é o da Ligação MSMQ Transacionada.
A comunicação com o serviço ocorre no âmbito de uma transação. O serviço lê mensagens da fila, executa a operação e, em seguida, exibe os resultados da operação. O aplicativo também cria uma fila de mensagens de letra morta.
//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
//Client implementation code.
class Client
{
static void Main()
{
// Get MSMQ queue name from app settings in configuration
string deadLetterQueueName = ConfigurationManager.AppSettings["deadLetterQueueName"];
// Create the transacted MSMQ queue for storing dead message if necessary.
if (!MessageQueue.Exists(deadLetterQueueName))
MessageQueue.Create(deadLetterQueueName, true);
// Create a proxy with given client endpoint configuration
OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");
// 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);
// Complete the transaction.
scope.Complete();
}
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
A configuração do cliente especifica uma curta duração para que a mensagem chegue ao serviço. Se a mensagem não puder ser transmitida dentro da duração especificada, a mensagem expirará e será movida para a fila de mensagens mortas.
Observação
É possível que o cliente entregue a mensagem para a fila de serviço dentro do tempo especificado. Para garantir que você veja o serviço de carta morta em ação, execute o cliente antes de iniciar o serviço. A mensagem ultrapassa o tempo limite e é entregue ao serviço de mensagens não entregues.
O aplicativo deve definir qual fila usar como sua fila de letra morta. Se nenhuma fila for especificada, a fila de letras mortas transacional padrão em todo o sistema será usada para enfileirar mensagens inativas. Neste exemplo, o aplicativo cliente especifica sua própria fila de letras mortas do aplicativo.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- use appSetting to configure MSMQ Dead Letter queue name -->
<add key="deadLetterQueueName" value=".\private$\ServiceModelSamplesOrdersAppDLQ"/>
</appSettings>
<system.serviceModel>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="PerAppDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="PerAppDLQBinding"
deadLetterQueue="Custom"
customDeadLetterQueue="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
timeToLive="00:00:02"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
O serviço de mensagens não entregues lê mensagens da fila de mensagens não entregues. O serviço de mensagens mortas executa o IOrderProcessor contrato. Sua implementação, no entanto, não é para processar pedidos. O serviço de mensagens mortas é um serviço de cliente e não tem a facilidade de processar pedidos.
Observação
A fila de mensagens mortas é uma fila de cliente e é local do gestor de filas do cliente.
A implementação do serviço de mensagens mortas verifica o motivo pelo qual uma mensagem falhou na entrega e toma medidas corretivas. O motivo de uma falha de mensagem é capturado em duas enumerações DeliveryFailure e DeliveryStatus. Você pode recuperar o MsmqMessageProperty do OperationContext conforme mostrado no exemplo de código a seguir:
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp =
OperationContext.Current.IncomingMessageProperties[
MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ",
mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}",
mqProp.DeliveryFailure);
Console.WriteLine();
…
}
As mensagens na fila de mensagens mortas são mensagens endereçadas ao serviço que está processando a mensagem. Portanto, quando o serviço de mensagens de dead-letter lê mensagens da fila, a camada de canal do Windows Communication Foundation (WCF) localiza a incompatibilidade nos pontos de extremidade e não encaminha a mensagem. Nesse caso, a mensagem é endereçada ao serviço de processamento de pedidos, mas é recebida pelo serviço de mensagens mortas. Para receber uma mensagem endereçada a um ponto de extremidade diferente, um filtro de endereço para corresponder a qualquer endereço é especificado no ServiceBehavior. Isso é necessário para processar com êxito as mensagens que são lidas da fila de mensagens mortas.
Neste exemplo, o serviço de mensagem de letra morta reenvia a mensagem se o motivo da falha for o tempo limite da mensagem. Para todos os outros motivos, exibe a falha de entrega, como mostrado no código de exemplo a seguir:
// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single, AddressFilterMode=AddressFilterMode.Any)]
public class PurchaseOrderDLQService : IOrderProcessor
{
OrderProcessorClient orderProcessorService;
public PurchaseOrderDLQService()
{
orderProcessorService = new OrderProcessorClient("OrderProcessorEndpoint");
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ", mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}", mqProp.DeliveryFailure);
Console.WriteLine();
// resend the message if timed out
if (mqProp.DeliveryFailure == DeliveryFailure.ReachQueueTimeout ||
mqProp.DeliveryFailure == DeliveryFailure.ReceiveTimeout)
{
// re-send
Console.WriteLine("Purchase order Time To Live expired");
Console.WriteLine("Trying to resend the message");
// reuse the same transaction used to read the message from dlq to enqueue the message to app. queue
orderProcessorService.SubmitPurchaseOrder(po);
Console.WriteLine("Purchase order resent");
}
}
// Host the service within this EXE console application.
public static void Main()
{
// Create a ServiceHost for the PurchaseOrderDLQService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(PurchaseOrderDLQService)))
{
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The dead letter service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
}
O exemplo a seguir mostra a configuração de uma mensagem de letra morta:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.PurchaseOrderDLQService">
<!-- Define NetMsmqEndpoint in this case, DLQ end point to read messages-->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
binding="netMsmqBinding"
bindingConfiguration="DefaultBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</service>
</services>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="SystemDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="DefaultBinding" />
<binding name="SystemDLQBinding"
deadLetterQueue="System"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Ao executar o exemplo, existem 3 executáveis para se ver como a fila de mensagens mortas funciona para cada aplicação: o cliente, o serviço e um serviço de fila de mensagens mortas que lê a fila para cada aplicação e reenvia a mensagem para o serviço. Todos são aplicativos de console com saída em janelas de console.
Observação
Como o enfileiramento está em uso, o cliente e o serviço não precisam estar funcionando ao mesmo tempo. Você pode executar o cliente, desligá-lo e, em seguida, iniciar o serviço e ele ainda recebe suas mensagens. Você deve iniciar o serviço e desligá-lo para que a fila possa ser criada.
Ao executar o cliente, o cliente exibe a mensagem:
Press <ENTER> to terminate client.
O cliente tentou enviar a mensagem, mas com um curto tempo limite, a mensagem expirou e agora está na fila de mensagens mortas para cada aplicativo.
Em seguida, execute o serviço de mensagens perdidas, o que lê a mensagem, exibe o código de erro e reenvia a mensagem novamente para o serviço.
The dead letter service is ready.
Press <ENTER> to terminate service.
Submitting purchase order did not succeed
Message Delivery Status: InDoubt
Message Delivery Failure: ReachQueueTimeout
Purchase order Time To Live expired
Trying to resend the message
Purchase order resent
O serviço é iniciado e, em seguida, lê a mensagem reenviada e processa-a.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 97897eff-f926-4057-a32b-af8fb11b9bf9
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
Verifique se você executou o procedimento de instalação do One-Time 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 Filas de Mensagens Privadase selecione Nova, Fila Privada.
Marque a caixa Transacional .
Digite
ServiceModelSamplesTransactedcomo 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 numa configuração de um único computador ou cruzada, altere adequadamente os nomes das filas, substituindo localhost pelo nome completo do computador, e siga as instruções em Executar os exemplos do Windows Communication Foundation.
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
Nonemostrado 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 do ponto de
bindingConfigurationextremidade.Certifique-se de alterar a configuração no DeadLetterService, no servidor e no cliente antes de executar o exemplo.
Observação
Definir
security modecomoNoneé equivalente a definirMsmqAuthenticationMode,MsmqProtectionLeveleMessagesegurança comoNone.
Observações
Por padrão, com o transporte de binding netMsmqBinding, a segurança está habilitada. Duas propriedades, MsmqAuthenticationMode e MsmqProtectionLevel, juntas 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".