本主题讨论客户端如何寻址从队列读取的服务,以及服务终结点如何映射到队列。 作为提醒,下图显示了经典 Windows Communication Foundation (WCF) 排队应用程序部署。
要使客户端将消息发送到服务,客户端会将消息发送到目标队列。 要使服务从队列中读取消息,它会将其侦听地址设置为目标队列。 WCF 中的寻址是基于统一资源标识符(URI)的,而消息队列(MSMQ)队列名称不是基于 URI 的。 因此,必须了解如何使用 WCF 解决 MSMQ 中创建的队列问题。
MSMQ 寻址
MSMQ 使用路径和格式名称来标识队列。 路径指定主机名称和 QueueName
。 (可选)在主机名与Private$
之间,可以插入QueueName
以指示未在 Active Directory 目录服务中发布的专用队列。
路径名称映射到“FormatNames”,以确定地址的其他方面,包括路由和队列管理器传输协议。 队列管理器支持两种传输协议:本机 MSMQ 协议和 SOAP 可靠消息传送协议(SRMP)。
有关 MSMQ 路径和格式名称的详细信息,请参阅 “关于消息队列”。
NetMsmqBinding 和服务寻址
将消息寻址到服务时,会根据用于通信的传输选择 URI 中的方案。 WCF 中的每个传输都具有唯一的方案。 该方案必须反映用于通信的传输的性质。 例如,net.tcp、net.pipe、HTTP 等。
WCF 中的 MSMQ 排队传输协议公开 net.msmq 方案。 使用 net.msmq 方案寻址的任何消息都使用 MSMQ 排队传输协议通道上的 NetMsmqBinding
发送。
WCF 中队列的寻址基于以下模式:
net.msmq: // <host-name> / [private/] <queue-name>
地点:
< host-name> 是托管目标队列的计算机的名称。
[private] 是可选的。 它在对作为专用队列的目标队列寻址时使用。 若要对公共队列寻址,不能指定 private。 请注意,与 MSMQ 路径不同,WCF URI 窗体中没有“$”。
< queue-name> 是队列的名称。 队列名还可以引用子队列。 因此,<queue-name = ><>[;sub-queue-name]。
示例 1:要访问在计算机 abc.adatum.com 上托管的专用队列 PurchaseOrders,URI 将为 net.msmq://abc.adatum.com/private/PurchaseOrders。
示例 2:若要访问托管在电脑 def.adatum.com 上的公共队列 AccountsPayable,URI 应为 net.msmq://def.adatum.com/AccountsPayable。
队列地址用作侦听器从中读取消息的侦听 URI。 换言之,队列地址等效于 TCP 套接字的侦听端口。
从队列中读取消息的终结点必须使用以前在打开 ServiceHost 时指定的同一方案指定队列地址。 有关示例,请参阅 NET MSMQ 绑定。
队列中存在多个协定
队列中的每条消息可以实现不同的协议。 在这种情况下,必须有以下之一为真,才能成功读取和处理所有消息:
指定实现所有协定的服务的终结点。 这是建议的方法。
指定具有不同协定的多个终结点,但确保所有终结点都使用相同的
NetMsmqBinding
对象。 ServiceModel 中的调度逻辑使用一个消息泵,它从传输通道中读取消息以进行调度,并最终根据相应的协定将消息多路分解到不同的终结点。 消息泵是为侦听 URI/绑定对创建的。 队列地址被排队侦听器用作侦听 URI。 通过让所有终结点使用相同的绑定对象,可以确保使用单个消息泵来读取消息,并且根据协定将消息多路分解到相关终结点。
SRMP 消息传递
如前所述,可以使用 SRMP 协议进行队列到队列传输。 当 HTTP 传输在传输队列和目标队列之间传输消息时,通常使用此方法。
若要使用 SRMP 传输协议,请使用 net.msmq URI 方案对消息进行寻址,如前所述,并在属性QueueTransferProtocol
中NetMsmqBinding
指定 SRMP 或安全 SRMP 的选择。
指定 QueueTransferProtocol
属性是一项仅发送的功能。 这是客户端指示要使用哪种队列传输协议。
使用 Active Directory
MSMQ 支持 Active Directory 集成。 当 MSMQ 与 Active Directory 集成一起安装时,计算机必须是 Windows 域的一部分。 Active Directory 用于发布用于发现的队列;此类队列称为 公共队列。 处理队列时,可以使用 Active Directory 解析队列。 这类似于域名系统(DNS)用于解析网络名称的 IP 地址的方式。 该 UseActiveDirectory
属性是一个布尔值 NetMsmqBinding
,指示排队通道是否必须使用 Active Directory 解析队列 URI。 默认情况下,它设置为 false
.
UseActiveDirectory
如果该属性设置为true
,则排队通道使用 Active Directory 将 net.msmq:// URI 转换为格式名称。
该 UseActiveDirectory
属性仅对发送消息的客户端有意义,因为它用于在发送消息时解析队列的地址。
将 net.msmq URI 映射到消息队列格式名
排队通道负责将提供给通道的 net.msmq URI 名称映射到 MSMQ 格式名。 下表总结了用于在它们之间映射的规则。
基于 WCF URI 的队列地址 | 使用 Active Directory 属性 | 队列传输协议属性 | 生成的 MSMQ 格式名称 |
---|---|---|---|
Net.msmq://<machine-name>/private/abc |
False(默认值) | Native(默认值) | DIRECT=OS:machine-name\private$\abc |
Net.msmq://<machine-name>/private/abc |
假 | SRMP | DIRECT=http://machine/msmq/private$/abc |
Net.msmq://<machine-name>/private/abc |
真 实 | 本地 |
PUBLIC=some-guid (队列的 GUID) |
从 Dead-Letter 队列或 Poison-Message 队列读取消息
若要从目标队列的“有毒消息队列”这一子队列中读取消息,请使用该子队列的地址打开 ServiceHost
。
示例:从本地计算机的 PurchaseOrders 专用队列的病毒消息队列中读取消息的服务将按 net.msmq://localhost/private/PurchaseOrders;poison 寻址。
若要从系统事务死信队列中读取消息,URI 必须采用以下形式:net.msmq://localhost/system$;DeadXact。
若要从系统非事务死信队列读取消息,URI 必须采用以下形式:net.msmq://localhost/system$;DeadLetter。
使用自定义死信队列时,请注意死信队列必须驻留在本地计算机上。 因此,死信队列的 URI 被限制为以下形式:
net.msmq: //localhost/ [private/] <custom-dead-letter-queue-name>。
WCF 服务验证它接收到的消息的目标队列是否都是它正在侦听的特定队列。 如果消息的目标队列与其找到的队列不匹配,则服务不会处理该消息。 这存在一个问题:侦听死信队列的服务必须寻址,因为死信队列中的任何消息都需要传递到别处。 若要从死信队列或病毒队列中读取消息,必须使用带有 ServiceBehavior
参数的 Any。 有关示例,请参阅死信队列。
MsmqIntegrationBinding 和服务寻址
MsmqIntegrationBinding
用于与传统 MSMQ 应用程序通信。 为了简化与现有 MSMQ 应用程序的互作,WCF 仅支持格式名称寻址。 因此,使用此绑定发送的消息必须符合 URI 方案:
msmq.formatname:<MSMQ-format-name>>
MSMQ 格式名称采用 MSMQ 在 “关于消息队列”中指定的形式。
请注意,当使用MsmqIntegrationBinding
接收队列中的消息时,只能使用直接格式名称和公共或专用格式名称(后者需要 Active Directory 集成)。 但是,建议您使用直接格式名。 例如,在 Windows Vista 上,使用任何其他格式名称会导致错误,因为系统尝试打开一个子队列,该子队列只能使用直接格式名称打开。
在使用 MsmqIntegrationBinding
对 SRMP 进行寻址时,不需要在直接格式名中添加 /msmq/ 来帮助 Internet 信息服务 (IIS) 进行调度。 例如:使用 SRMP 协议处理队列 abc 时,应使用 DIRECT=http://adatum.com/msmq/private$/abc
替代 DIRECT=http://adatum.com/private$/abc
。
请注意,不能将 net.msmq:// 地址与 MsmqIntegrationBinding
一起使用。 由于 MsmqIntegrationBinding
支持自由格式的 MSMQ 格式名称寻址,因此可以使用使用此绑定的 WCF 服务在 MSMQ 中使用多播和通讯组列表功能。 一个例外是在使用 CustomDeadLetterQueue
时指定 MsmqIntegrationBinding
。 它必须采用 net.msmq:// 的形式,就像使用 NetMsmqBinding
时指定的一样。