Vinculação MSMQ transacionada
O exemplo Transacted demonstra como executar a comunicação em fila transacionada usando o serviço de enfileiramento de mensagens (MSMQ).
Nota
O procedimento de configuração e as instruções de compilação para este exemplo estão localizados no final deste tópico.
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.
Quando as transações são usadas para enviar e receber mensagens, na verdade existem duas transações separadas. Quando o cliente envia mensagens dentro do escopo de uma transação, a transação é local para o cliente e o gerenciador de filas do cliente. Quando o serviço recebe mensagens dentro do escopo da transação, a transação é local para o serviço e o gerenciador de filas de recebimento. É muito importante lembrar que o cliente e o serviço não estão participando da mesma transação; em vez disso, eles estão usando transações diferentes ao executar suas operações (como enviar e receber) com a fila.
Neste exemplo, o cliente envia um lote de mensagens para o serviço de dentro do escopo de uma transação. As mensagens enviadas para a fila são então recebidas pelo serviço dentro do escopo de transação definido pelo serviço.
O contrato de serviço é IOrderProcessor
, conforme mostrado no código de exemplo a seguir. A interface define um serviço unidirecional que é adequado para uso com filas.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
O comportamento de serviço define um comportamento de operação com TransactionScopeRequired
definido como true
. Isso garante que o mesmo escopo de transação usado para recuperar a mensagem da fila seja usado por todos os gerentes de recursos acessados pelo método. Ele também garante que, se o método lançar uma exceção, a mensagem será retornada para a fila. Sem definir esse comportamento de operação, um canal enfileirado cria uma transação para ler a mensagem da fila e a confirma automaticamente antes do envio, de modo que, se a operação falhar, a mensagem será perdida. O cenário mais comum é que as operações de serviço se alistem na transação usada para ler a mensagem da fila, conforme demonstrado no código a seguir.
// This service class that implements the service contract.
// This added code writes output to the console window.
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
}
…
}
O serviço é auto-hospedado. Ao usar o transporte MSMQ, a fila usada deve ser criada com antecedência. Isso pode ser feito manualmente ou através de código. Neste exemplo, o serviço contém código para verificar a existência da fila e criar a fila se ela não existir. O nome da fila é lido a partir do arquivo de configuração. O endereço base é usado pela ServiceModel Metadata Utility Tool (Svcutil.exe) para gerar o proxy para o serviço.
// Host the service within this EXE console application.
public static void Main()
{
// Get the MSMQ queue name from appSettings in configuration.
string queueName = ConfigurationManager.AppSettings["queueName"];
// Create the transacted MSMQ queue if necessary.
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
// Create a ServiceHost for the OrderProcessorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
{
// Open the ServiceHost 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();
// Close the ServiceHost to shut down the service.
serviceHost.Close();
}
}
O nome da fila MSMQ é especificado em uma seção appSettings do arquivo de configuração, conforme mostrado na configuração de exemplo a seguir.
<appSettings>
<add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
Nota
O nome da fila usa um ponto (.) para o computador local e separadores de barra invertida em seu caminho ao criar a fila usando System.Messaging. O ponto de extremidade do Windows Communication Foundation (WCF) usa o endereço da fila com esquema net.msmq, usa "localhost" para indicar o computador local e usa barras em seu caminho.
O cliente cria um escopo de transação. A comunicação com a fila ocorre dentro do escopo da transação, fazendo com que ela seja tratada como uma unidade atômica onde todas as mensagens são enviadas para a fila ou nenhuma das mensagens é enviada para a fila. A transação é confirmada chamando Complete o escopo da transação.
// Create a client.
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);
// 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();
Para verificar se as transações estão funcionando, modifique o cliente comentando o escopo da transação conforme mostrado no código de exemplo a seguir, reconstrua a solução e execute o cliente.
//scope.Complete();
Como a transação não é concluída, as mensagens não são enviadas para a fila.
Quando você executa o exemplo, as atividades do cliente e do serviço são exibidas nas janelas do console do serviço e do cliente. Você pode ver o serviço receber mensagens do cliente. Pressione ENTER em cada janela do console para desligar o serviço e o cliente. Observe que, 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 as mensagens.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 7b31ce51-ae7c-4def-9b8b-617e4288eafd
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 entre computadores, siga as instruções em Executando os exemplos do Windows Communication Foundation.
Por padrão, a segurança de transporte está habilitada NetMsmqBinding. Há duas propriedades relevantes para a segurança MsmqAuthenticationMode de transporte MSMQ e MsmqProtectionLevel. 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 e a opção de integração do Ative Directory para MSMQ deve estar instalada. Se você executar este exemplo em um computador que não satisfaz esses critérios, você receberá um erro.
Para executar o exemplo em um computador associado a um grupo de trabalho ou sem integração com o Ative Directory
Se o computador não fizer parte de um domínio ou não tiver a integração com o Ative Directory instalada, desative a segurança de transporte definindo o modo de autenticação e o nível de proteção como
None
mostrado no código de configuração de exemplo a seguir.<system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.OrderProcessorService" behaviorConfiguration="OrderProcessorServiceBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/> </baseAddresses> </host> <!-- Define NetMsmqEndpoint. --> <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTransacted" binding="netMsmqBinding" bindingConfiguration="Binding1" contract="Microsoft.ServiceModel.Samples.IOrderProcessor" /> <!-- The mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex. --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <bindings> <netMsmqBinding> <binding name="Binding1"> <security mode="None" /> </binding> </netMsmqBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="OrderProcessorServiceBehavior"> <serviceMetadata httpGetEnabled="True"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Certifique-se de alterar a configuração no servidor e no cliente antes de executar o exemplo.
Nota
Definir
security mode
comoNone
é equivalente a definir MsmqAuthenticationMode, MsmqProtectionLeveleMessage
segurança paraNone
.