Associação transacionada do MSMQ
O exemplo de Transacionada demonstra como executar a comunicação na fila transacionada usando o MSMQ (Enfileiramento de Mensagens).
Observação
Os procedimentos de instalação e as instruções de build desse exemplo estão localizadas no final deste tópico.
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.
Quando as transações são usadas para enviar e receber mensagens, na verdade, há 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 no 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 recebidas pelo serviço dentro do escopo de transação definido pelo serviço.
O contrato de serviço IOrderProcessor
, como mostrado no código de amostra a seguir. A interface 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);
}
O comportamento do 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 gerenciador de recursos acessados pelo método. Também garante que, se o método gerar 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 de expedir 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. Quando o transporte MSMQ é usado, a fila usada precisa ser criada com antecedência. Isso pode ser feito manualmente ou por meio do 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 no arquivo de configuração. O endereço básico é usado pela Ferramenta Utilitário de Metadados ServiceModel (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 da amostra.
<appSettings>
<add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
Observação
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 WCF (Windows Communication Foundation) usa o endereço da fila com o esquema net.msmq, usa "localhost" para indicar o computador local e usa barras de encaminhamento em seu caminho.
O cliente cria um escopo de transação. A comunicação com a fila ocorre no escopo da transação, fazendo com que ela seja tratada como uma unidade atômica em que todas as mensagens são enviadas para a fila ou nenhuma das mensagens são enviadas para a fila. A transação é confirmada chamando Complete no 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, recompile a solução e execute o cliente.
//scope.Complete();
Como a transação não foi concluída, as mensagens não são enviadas para a fila.
Quando você executa o exemplo, as atividades de cliente e de serviço são exibidas nas janelas do serviço e do console 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 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 iniciar o serviço e ele ainda receberá 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
Verifique se você executou 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 do 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 NovaFila Privada.
Marque a caixa Transacional.
Insira
ServiceModelSamplesTransacted
como 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 de computador único ou entre computadores, siga as instruções em Como executar as amostras do Windows Communication Foundation.
Por padrão com a NetMsmqBinding, a segurança do transporte está habilitada. Há duas propriedades relevantes para a segurança do transporte MSMQ, MsmqAuthenticationMode 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 Active Directory para o MSMQ precisa ser instalada. Se você executar este exemplo em um computador que não atenda a esses critérios, receberá um erro.
Para executar o exemplo em um computador que ingressou em um grupo de trabalho ou sem integração com o Active Directory
Se o computador não fizer parte de um domínio ou não tiver a integração com o Active Directory instalada, desative a segurança do transporte definindo o modo de autenticação e o nível de proteção como
None
, conforme mostrado no exemplo de código de configuração 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>
Verifique se você alterou a configuração no servidor e no cliente antes de executar o exemplo.
Observação
Definir
security mode
comoNone
é equivalente a configurar a segurança MsmqAuthenticationMode, MsmqProtectionLevel eMessage
comoNone
.