自定义多路分解器
本示例演示如何将 MSMQ 消息头映射到不同服务操作,以便使用 MsmqIntegrationBinding 的 Windows Communication Foundation (WCF) 服务不再像 到 Windows Communication Foundation 的消息队列 和 Windows Communication Foundation 到消息队列 示例中那样限于使用一个服务操作。
本示例中的服务是自承载控制台应用程序,通过它可以观察接收排队消息的服务。
此服务协定是 IOrderProcessor
,它定义了适合与队列一起使用的单向服务。
[ServiceContract]
[KnownType(typeof(PurchaseOrder))]
[KnownType(typeof(String))]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true, Name = "SubmitPurchaseOrder")]
void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);
[OperationContract(IsOneWay = true, Name = "CancelPurchaseOrder")]
void CancelPurchaseOrder(MsmqMessage<string> ponumber);
}
MSMQ 消息没有 Action 标头。无法自动将不同的 MSMQ 消息映射到操作协定。所以只能有一个操作协定。为了克服此限制,服务实现 IDispatchOperationSelector 接口的 SelectOperation 方法。通过 SelectOperation 方法,服务可以将给定的消息头映射到特定服务操作。在本示例中,将消息的标签标头映射到服务操作。操作协定的 Name
参数确定必须为给定的消息标签调度哪个服务操作。例如,如果消息的标签标头包含“SubmitPurchaseOrder”,则调用“SubmitPurchaseOrder”服务操作。
public class OperationSelector : IDispatchOperationSelector
{
public string SelectOperation(ref System.ServiceModel.Channels.Message message)
{
MsmqIntegrationMessageProperty property = MsmqIntegrationMessageProperty.Get(message);
return property.Label;
}
}
服务必须实现 IContractBehavior 接口的 ApplyDispatchBehavior 方法,如下面的示例代码所示。这会将自定义 OperationSelector
应用于服务框架调度运行时。
void IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
{
dispatch.OperationSelector = new OperationSelector();
}
在到达 OperationSelector 之前,消息必须通过调度程序的 ContractFilter。默认情况下,如果在由服务实现的任何协定上找不到消息操作,则会拒绝该消息。为了避免这种阻碍的发生,我们实现了一个名为 MatchAllFilterBehavior
的 IEndpointBehavior,它通过应用 MatchAllMessageFilter 允许任何消息通过 ContractFilter
,如下所示。
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ContractFilter = new MatchAllMessageFilter();
}
当服务接收到消息时,会使用标签标头提供的信息调度相应的服务操作。消息正文反序列化为 PurchaseOrder
对象,如下面的示例代码所示。
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg)
{
PurchaseOrder po = (PurchaseOrder)msg.Body;
Random statusIndexer = new Random();
po.Status = (OrderStates)statusIndexer.Next(3);
Console.WriteLine("Processing {0} ", po);
}
服务是自承载服务。使用 MSMQ 时,必须提前创建所使用的队列。可以手动或通过代码完成此操作。在本示例中,服务包含用以检查队列是否存在的代码,并在队列不存在时创建该队列。从配置文件中读取队列名称。
public static void Main()
{
// Get MSMQ queue name from app settings in configuration
string queueName = ConfigurationManager.AppSettings["orderQueueName"];
// Create the transacted MSMQ queue if necessary.
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
// Create a ServiceHost for the CalculatorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
{
ServiceEndpoint endpoint = serviceHost.Description.Endpoints[0];
endpoint.Behaviors.Add(new MatchAllFilterBehavior());
//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.ReadLine();
// Close the ServiceHost to shutdown the service.
serviceHost.Close();
}
}
MSMQ 队列名称是在配置文件的 appSettings 节中指定的。
提示
队列名称使用圆点 (.)来表示本地计算机,并在其路径中使用反斜杠分隔符。WCF 终结点地址指定 msmq.formatname 方案,并为本地计算机使用 localhost。方案后面是根据 MSMQ 格式名寻址指南正确格式化的队列地址。
<appSettings>
<!-- Use appSetting to configure the MSMQ queue name. -->
<add key="queueName" value=".\private$\Orders" />
</appSettings>
提示
此示例要求安装 Message Queuing(消息队列)。
启动服务并运行客户端。
下面的输出显示在客户端上。
Placed the order:Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
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
Cancelled the Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
Press <ENTER> to terminate client.
下面的输出必须显示在服务上。
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
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: Shipped
Purchase Order 28fc457a-1a56-4fe0-9dde-156965c21ed6 is cancelled
设置、生成和运行示例
若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。
若要用单机配置或跨计算机配置来运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。
跨计算机运行示例
将 \service\bin\ 文件夹(在语言特定文件夹内)中的服务程序文件复制到服务计算机上。
将 \client\bin\ 文件夹(在语言特定文件夹内)中的客户端程序文件复制到客户端计算机上。
在 Client.exe.config 文件中,更改 orderQueueName 以指定服务计算机名称,而不是使用“.”。
在服务计算机上的命令提示符下启动 Service.exe。
在客户端计算机上,在命令提示符下启动 Client.exe。
另请参见
其他资源
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.