https://msdn.microsoft.com/zh-cn/biztalk/ms751493
本示例演示如何使用消息队列 (MSMQ) 执行已经过事务处理的排队通信。
|
|
|---|
|
本主题的末尾介绍了此示例的设置过程和生成说明。 |
因此,不必同时运行服务和客户端便可使用队列进行通信。
请务必牢记,客户端和服务不会参与同一个事务;实际上,它们在对队列执行操作(如发送和接收)时使用的是不同的事务。
然后,服务在服务定义的事务范围内接收发送到队列的消息。
此接口定义了适合与队列一起使用的单向服务。
对于服务操作而言,最常见的方案是在用于从队列中读取消息的事务中进行登记,如下面的代码中所示。
// 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);
}
…
}
ServiceModel 元数据实用工具 (Svcutil.exe) 使用该基址来生成服务的代理。
// 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();
}
}
MSMQ 队列名称在配置文件的 appSettings 节中指定,如以下示例配置所示。
<appSettings>
<add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
|
|
|---|
|
Windows Communication Foundation (WCF) 终结点使用具有 net.msmq 方案的队列地址,使用“localhost”来表示本地计算机,并在其路径中使用正斜杠。 |
Complete 可以提交事务。
// 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();
若要验证事务正在运行,请按照下面的示例代码注释事务范围来修改客户端,重新生成解决方案并运行客户端。
//scope.Complete();
因为事务没有完成,所以消息未发送到队列。
可以先运行客户端,再将其关闭,然后启动服务,这样服务仍然会收到客户端的消息。
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
设置、生成和运行示例
-
Windows Communication Foundation 示例的一次性安装过程。
-
执行下面的步骤来在 Windows 2008 中创建队列。
-
在 Visual Studio 2012 中打开服务器管理器。
-
展开“功能”选项卡。
-
右击“私有消息队列”,然后选择“新建”和“专用队列”。
-
选中“事务性”框。
-
输入 ServiceModelSamplesTransacted 作为新队列的名称。
-
-
生成 Windows Communication Foundation 示例中的说明进行操作。
-
运行 Windows Communication Foundation 示例中的说明进行操作。
如果在未满足这些条件的计算机上运行此示例,将会收到错误。
在加入到工作组或在没有 Active Directory 集成的计算机上运行示例
-
如果计算机不是域成员或尚未安装 Active Directory 集成,请将身份验证模式和保护级别设置为 None 以关闭传输安全性,如下面的示例配置代码所示。
<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 explosed 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> -
确保在运行示例前更改服务器和客户端上的配置。
注意
将 securitymode 设置为 None 等效于将 、 和 Message 安全设置为 None。