双向示例演示如何通过 MSMQ 执行事务处理双向排队通信。 此示例使用 netMsmqBinding 绑定。 在本例中,服务是一个自承载的控制台应用程序,通过它可以观察服务接收排队消息。
注释
本示例的设置过程和生成说明位于本主题末尾。
该示例基于事务处理 MSMQ 绑定。
在排队通信中,客户端使用队列与服务通信。 客户端将消息发送到队列,服务从队列接收消息。 因此,服务与客户端不必同时运行,才能使用队列进行通信。
此示例演示了使用队列的双向通信。 客户端从事务范围内向队列发送采购订单。 服务接收订单、处理订单,然后在事务范围内使用队列中订单的状态回调客户端。 为了便于双向通信,客户端和服务都使用队列以便将采购订单和订单状态排入队列。
服务协定 IOrderProcessor 定义了适合使用队列的单向服务操作。 服务操作包括用于向其发送订单状态的答复终结点。 回复终结点是队列的 URI,用于将订单状态发送回客户端。 订单处理应用程序实现此协定。
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po, string
reportOrderStatusTo);
}
用于发送订单状态的回复协定由客户端指定。 客户端实现订单状态协定。 该服务使用此协定生成的代理将订单状态发送回客户端。
[ServiceContract]
public interface IOrderStatus
{
[OperationContract(IsOneWay = true)]
void OrderStatus(string poNumber, string status);
}
服务操作处理提交的采购订单。 对服务操作应用 OperationBehaviorAttribute 以在用于从队列中接收消息的事务中指定自动登记,并指定在服务操作完成时事务自动完成。 该 Orders 类封装订单处理功能。 在这种情况下,它将采购订单添加到字典中。
Orders 类中的操作可以使用服务操作登记的事务。
服务作除了处理提交的采购订单外,还会回复客户端有关订单的状态。
[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();
}
MSMQ 队列名称是在配置文件的 appSettings 部分中指定的。 服务的终结点在配置文件的 System.ServiceModel 节中定义。
注释
MSMQ 队列名称和终结点地址使用略有不同的寻址约定。 MSMQ 队列名称使用点号(.)来指代本地计算机,并使用反斜杠作为路径中的分隔符。 Windows Communication Foundation (WCF) 终结点地址指定一个 net.msmq: 方案,使用“localhost”来表示本地计算机,并在其路径中使用正斜杠。 若要从远程计算机上托管的队列中读取,请将“.”和“localhost”替换为远程计算机名称。
该服务是自托管的。 使用 MSMQ 传输时,必须提前创建使用的队列。 这可以手动或通过代码完成。 在此示例中,服务会检查队列是否存在,并在必要时创建队列。 队列名称从配置文件中读取。 ServiceModel 元数据实用工具工具(Svcutil.exe)使用基址生成服务的代理。
// 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();
}
}
客户端创建事务。 与队列的通信在事务范围内进行,从而可以将事务范围视为所有消息在其中成功或失败的原子单元。
// 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();
}
客户端代码实现 IOrderStatus 协定以便从服务接收订单状态。 在这种情况下,它会输出订单状态。
[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);
}
}
在方法中创建 Main 订单状态队列。 客户端配置包括用于托管订单状态服务的订单状态服务配置,如以下示例配置所示。
<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>
运行示例时,客户端和服务活动会显示在服务和客户端控制台窗口中。 可以看到服务从客户端接收消息。 在每个控制台窗口中按 Enter 可以关闭服务和客户端。
该服务显示采购订单信息,并指示它正在将订单状态发送回订单状态队列。
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
客户端显示服务发送的订单状态信息。
Press <ENTER> to terminate client.
Status of order 124a1f69-3699-4b16-9bcc-43147a8756fc:Pending
设置、生成和运行示例
确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。
若要生成解决方案的 C# 或 Visual Basic .NET 版本,请按照 生成 Windows Communication Foundation 示例中的说明进行操作。
若要在单台计算机或跨计算机配置中运行示例,请按照 运行 Windows Communication Foundation 示例中的说明进行操作。
注释
如果使用 Svcutil.exe 重新生成此示例的配置,请确保修改客户端配置中的终结点名称以匹配客户端代码。
默认情况下使用 NetMsmqBinding 启用传输安全。 MSMQ 传输安全性有两个相关属性, MsmqAuthenticationModeMsmqProtectionLevel.默认情况下,身份验证模式设置为Windows,保护级别设置为 。Sign 要使 MSMQ 提供身份验证和签名功能,它必须是域的一部分,并且必须安装 MSMQ 的 Active Directory 集成选项。 如果在不符合这些条件的计算机上运行此示例,则会收到错误。
在加入到工作组或在没有 Active Directory 集成的计算机上运行示例
如果计算机不是域的一部分,或者未安装 Active Directory 集成,请将身份验证模式和保护级别设置为
None关闭传输安全性,如以下示例配置所示:<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>关闭客户端配置的安全性将生成下面的内容:
<?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>此示例的服务在
OrderProcessorService中创建一个绑定。 在实例化绑定后添加一行代码,以将安全模式设置为None。NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding(); msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;在运行示例之前,请确保在服务器和客户端上更改配置。
注释
设置
security mode为None等同于将MsmqAuthenticationMode、MsmqProtectionLevel或Message的安全设置为None。