Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O exemplo de DeadLetter demonstra como lidar e processar mensagens que falharam na entrega. Ela é baseada na amostra de Associação transacionada do MSMQ. Este exemplo usa a netMsmqBinding associação. O serviço é um aplicativo de console auto-hospedado para permitir que você observe o serviço que está recebendo mensagens na fila.
Observação
O procedimento de instalação e as instruções de build para este exemplo estão localizados no final deste tópico.
Observação
Esta amostra demonstra cada fila de mensagens de inatividade do aplicativo que só está disponível 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 no Windows XP.
Na comunicação na 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. Portanto, o serviço e o cliente não precisam estar em execução ao mesmo tempo para se comunicar usando uma fila.
Como a comunicação enfileirada pode envolver uma determinada quantidade de dormência, talvez você queira associar um valor de vida útil à mensagem para garantir que a mensagem não seja entregue ao aplicativo se ela tiver passado do tempo. 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 na mensagem expirou ou a mensagem falhou na entrega, a mensagem é colocada em uma fila de mensagens mortas. O aplicativo de envio pode ler as mensagens na fila de mensagens não entregues e executar ações corretivas, que podem variar desde nenhuma ação até corrigir os motivos da falha na entrega e reenviar a mensagem.
A fila de mensagens de inatividade na associação NetMsmqBinding é expressa nas seguintes propriedades:
DeadLetterQueue Propriedade para expressar o tipo de fila de mensagens de inatividade exigido pelo cliente. Essa enumeração tem os seguintes valores:
None: nenhuma fila de mensagens de inatividade é exigida pelo cliente.System: a fila de mensagens de inatividade do sistema é usada para armazenar mensagens de inatividade. A fila de mensagens de inatividade do sistema é compartilhada por todos os aplicativos em execução no computador.Custom: uma fila de mensagens de inatividade personalizada especificada usando a propriedade CustomDeadLetterQueue é usada para armazenar mensagens de inatividade. Esse recurso só está disponível no Windows Vista. Isso é usado quando o aplicativo deve usar sua própria fila de mensagens de inatividade em vez de compartilhá-la com outros aplicativos em execução no mesmo computador.CustomDeadLetterQueue propriedade para expressar a fila específica a ser usada como uma fila de mensagens de inatividade. Isso só está disponível 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 "vida útil" para essas mensagens (cerca de 2 segundos). O cliente também especifica uma fila de mensagens de inatividade 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 na amostra é o da Associação transacionada do MSMQ.
A comunicação com o serviço ocorre no escopo de uma transação. O serviço lê mensagens da fila, executa a operação e exibe os resultados da operação. O aplicativo também cria uma fila de mensagens de inatividade para mensagens de inatividade.
//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 à fila de serviço dentro do tempo especificado. Para garantir que você veja o serviço de mensagens de inatividade em ação, execute o cliente antes de iniciar o serviço. A mensagem atinge o tempo limite e é entregue ao serviço de mensagens de inatividade.
O aplicativo deve definir qual fila usar como sua fila de mensagens de inatividade. Se nenhuma fila for especificada, a fila de mensagens de inatividade transacionais em todo o sistema padrão será usada para enfileirar mensagens de inatividade. Neste exemplo, o aplicativo cliente especifica sua própria fila de mensagens de inatividade 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 de inatividade lê mensagens da fila de mensagens de inatividade. O serviço de mensagem de inatividade implementa o contrato IOrderProcessor. No entanto, sua implementação não é destinada ao processamento de pedidos. O serviço de mensagem de inatividade é um serviço de cliente e não tem a facilidade de processar ordens.
Observação
A fila de mensagens de inatividade é uma fila de cliente e é local para o gerenciador de filas do cliente.
A implementação do serviço de mensagem de inatividade 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 código de exemplo 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 de inatividade são mensagens endereçadas ao serviço que está processando a mensagem. Portanto, quando o serviço de mensagem de inatividade lê mensagens da fila, a camada do canal do Windows Communication Foundation (WCF) localiza a incompatibilidade em pontos de extremidade e não envia a mensagem. Nesse caso, a mensagem é endereçada ao serviço de processamento de ordens, mas é recebida pelo serviço de mensagem de inatividade. 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 mensagens com sucesso que são lidas da fila de inatividade.
Nesta amostra, o serviço de mensagem de inatividade reenvia a mensagem se o motivo da falha for que a mensagem atingiu o tempo limite. Por todos os outros motivos, ele exibe a falha de entrega, conforme 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();
}
}
}
A amostra a seguir mostra a configuração de uma mensagem de inatividade:
<?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, há três executáveis a serem executados para ver como a fila de mensagens mortas funciona para cada aplicativo; o cliente, o serviço e um serviço de mensagens mortas que lê da fila de mensagens mortas para cada aplicativo e reenvia a mensagem para o serviço. Todos são aplicativos de console com saída em janelas de console.
Observação
Como a fila está em uso, o cliente e o serviço não precisam estar em funcionamento 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 como o tempo limite era curto, a mensagem expirou e agora está na fila de mensagens mortas para cada aplicativo.
Em seguida, você executa o serviço de mensagens mortas, que lê a mensagem e exibe o código de erro e reenvia a mensagem 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 começa e então lê a mensagem reenviada e a processa.
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 avulsa dos 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 do MSMQ. Siga estas etapas para criar uma fila no Windows 2008.
Abra o Gerenciador de Servidores no Visual Studio 2012.
Expanda a guia Recursos.
Clique com o botão direito do mouse em Filas de Mensagens Privadas e selecione NovaFila Privada.
Marque a caixa Transacional.
Insira
ServiceModelSamplesTransactedcomo o nome da nova fila.
Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.
Para executar o exemplo em uma configuração única ou em uma configuração entre computadores, altere os nomes da fila adequadamente, substituindo localhost pelo nome completo do computador e siga as instruções em Executar os Exemplos do Windows Communication Foundation.
Para executar a amostra em um computador ingressado em 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 ao definir o atributo
bindingConfigurationdo ponto de extremidade.Verifique se você alterou a configuração no DeadLetterService, no servidor e no cliente antes de executar o exemplo.
Observação
Configurar
security modeparaNoneequivale a configurar a segurança deMsmqAuthenticationMode,MsmqProtectionLeveleMessageparaNone.
Comentários
Por padrão com o transporte de associação netMsmqBinding, a segurança é habilitada. Duas propriedades, MsmqAuthenticationMode e MsmqProtectionLevel, juntas determinam o tipo de segurança de transporte. Por padrão, o modo de autenticação é definido Windows como 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, receberá o seguinte erro: "O certificado de enfileiramento de mensagem interna do usuário não existe".