双向示例演示如何通过 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
。