Comunicação bidirecional
O exemplo bidirecional demonstra como executar comunicação em fila bidirecional transacionada via MSMQ. Este exemplo usa a associação netMsmqBinding
. Neste caso, 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 compilação desse exemplo estão no final deste tópico.
Este exemplo se baseia na Associação transacionada do MSMQ.
Na comunicação na fila, o cliente se comunica com o serviço usando uma fila. O cliente envia mensagens para uma fila e 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.
Este exemplo demonstra a comunicação bidirecional usando filas. O cliente envia ordens de compra para a fila a partir do escopo de uma transação. O serviço recebe as ordens, processa e, em seguida, chama de volta o cliente com o status do pedido na fila no escopo de uma transação. Para facilitar a comunicação bidirecional, o cliente e o serviço usam filas para enfileirar ordens de compra e status das ordens.
O contrato IOrderProcessor
de serviço define operações de serviço unidirecionais que se adequam ao uso do enfileiramento. A operação de serviço inclui o ponto de extremidade de resposta a ser usado para enviar os status da ordem. O ponto de extremidade de resposta é a URI da fila que enviar o status da ordem de volta para o cliente. O aplicativo de processamento de ordens implementa esse contrato.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po, string
reportOrderStatusTo);
}
O contrato de resposta para o qual o status da ordem será enviado é especificado pelo cliente. O cliente implementa o contrato de status de ordens. O serviço usa o proxy gerado por esse contrato para enviar o status da ordem de volta para o cliente.
[ServiceContract]
public interface IOrderStatus
{
[OperationContract(IsOneWay = true)]
void OrderStatus(string poNumber, string status);
}
A operação de serviço processa a ordem de compra enviada. O OperationBehaviorAttribute é aplicado à operação de serviço para especificar a inscrição automática em uma transação usada para receber a mensagem da fila e a conclusão automática das transações após a conclusão da operação de serviço. A classe Orders
encapsula a funcionalidade de processamento de ordens. Nesse caso, ela adiciona a ordem de compra a um dicionário. A transação na qual a operação de serviço se inscreveu está disponível para as operações na classe Orders
.
A operação de serviço, além de processar a ordem de compra enviada, responde ao cliente sobre o status da ordem.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po, string reportOrderStatusTo)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
Console.WriteLine("Sending back order status information");
NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding("ClientCallbackBinding");
OrderStatusClient client = new OrderStatusClient(msmqCallbackBinding, new EndpointAddress(reportOrderStatusTo));
// Please note that the same transaction that is used to dequeue the purchase order is used
// to send back order status.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
client.OrderStatus(po.PONumber, po.Status);
scope.Complete();
}
//Close the client.
client.Close();
}
O nome da fila MSMQ é especificado em uma seção appSettings do arquivo de configuração. O ponto de extremidade do serviço é definido na seção System.ServiceModel do arquivo de configuração.
Observação
O nome da fila MSMQ e o endereço do ponto de extremidade usam convenções de endereçamento ligeiramente diferentes. O nome da fila MSMQ usa um ponto (.) para o computador local e separadores de barra invertida no caminho. O endereço de ponto de extremidade do WCF (Windows Communication Foundation) especifica um esquema net.msmq:, usa "localhost" para o computador local e usa barras no caminho. Para ler uma fila hospedada no computador remoto, substitua "." e "localhost" pelo nome do computador remoto.
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 verifica a existência da fila e a cria se necessário. 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 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();
}
}
O cliente cria uma 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 bem-sucedidas ou falham.
// Create a ServiceHost for the OrderStatus service type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderStatusService)))
{
// Open the ServiceHostBase to create listeners and start listening for order status messages.
serviceHost.Open();
// Create the purchase order.
...
// Create a client with given client endpoint configuration.
OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");
//Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
string hostName = Dns.GetHostName();
// Make a queued call to submit the purchase order.
client.SubmitPurchaseOrder(po, "net.msmq://" + hostName + "/private/ServiceModelSamplesTwo-way/OrderStatus");
// Complete the transaction.
scope.Complete();
}
//Close down the client.
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
// Close the ServiceHost to shutdown the service.
serviceHost.Close();
}
O código do cliente implementa o contrato IOrderStatus
para receber o status da ordem do serviço. Nesse caso, ele imprime o status da ordem.
[ServiceBehavior]
public class OrderStatusService : IOrderStatus
{
[OperationBehavior(TransactionAutoComplete = true,
TransactionScopeRequired = true)]
public void OrderStatus(string poNumber, string status)
{
Console.WriteLine("Status of order {0}:{1} ", poNumber ,
status);
}
}
A fila de status de ordens é criada no método Main
. A configuração do cliente inclui a configuração do serviço de status de ordens para hospedar esse serviço, conforme mostrado na configuração da amostra a seguir.
<appSettings>
<!-- Use appSetting to configure MSMQ queue name. -->
<add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderStatus" />
</appSettings>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderStatusService">
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderStatus"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderStatus" />
</service>
</services>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</client>
</system.serviceModel>
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.
O serviço exibe as informações do pedido de compra e indica que está enviando de volta o status da ordem para a fila de status dd ordens.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 124a1f69-3699-4b16-9bcc-43147a8756fc
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
Sending back order status information
O cliente exibe as informações de status da ordem enviadas pelo serviço.
Press <ENTER> to terminate client.
Status of order 124a1f69-3699-4b16-9bcc-43147a8756fc: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.
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 cruzado, siga as instruções em Como executar os exemplos do Windows Communication Foundation.
Observação
Se você usar Svcutil.exe para regenerar a configuração desta amostra, modifique os nomes de ponto de extremidade na configuração do cliente para corresponder ao código do cliente.
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 precisa 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.
Executar o exemplo em um computador integrante de um grupo de trabalho ou sem integração de diretórios ativos
Se o computador não fizer parte de um domínio ou não tiver a integração do 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 configuração a seguir:<configuration> <appSettings> <!-- Use appSetting to configure MSMQ queue name. --> <add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderProcessor" /> </appSettings> <system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"> <!-- Define NetMsmqEndpoint --> <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor" binding="netMsmqBinding" bindingConfiguration="TransactedBinding" contract="Microsoft.ServiceModel.Samples.IOrderProcessor" /> </service> </services> <bindings> <netMsmqBinding> <binding name="TransactedBinding" > <security mode="None" /> </binding> </netMsmqBinding> </bindings> </system.serviceModel> </configuration>
Desativar a segurança de uma configuração de cliente gera o seguinte:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <!-- Use appSetting to configure MSMQ queue name. --> <add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderStatus" /> </appSettings> <system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.OrderStatusService"> <!-- Define NetMsmqEndpoint --> <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderStatus" binding="netMsmqBinding" bindingConfiguration="TransactedBinding" contract="Microsoft.ServiceModel.Samples.IOrderStatus" /> </service> </services> <client> <!-- Define NetMsmqEndpoint --> <endpoint name="OrderProcessorEndpoint" address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor" binding="netMsmqBinding" bindingConfiguration="TransactedBinding" contract="Microsoft.ServiceModel.Samples.IOrderProcessor" /> </client> <bindings> <netMsmqBinding> <binding name="TransactedBinding" > <security mode="None" /> </binding> </netMsmqBinding> </bindings> </system.serviceModel> </configuration>
O serviço do exemplo cria uma associação em
OrderProcessorService
. Adicione uma linha de código depois que a associação for instanciada para definir o modo de segurança comoNone
.NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding(); msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;
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 ouMessage
comoNone
.