本部分包含有关在 Windows Communication Foundation(WCF)中使用队列的常见问题和故障排除帮助。
常见问题
问: 我使用了 WCF Beta 1,我安装了 MSMQ 修补程序。 是否需要删除修补程序?
答: 是的。 此修补程序不再受支持。 WCF 现在无需修补程序即可在 MSMQ 上运行。
问: MSMQ 有两个绑定: NetMsmqBinding 和 MsmqIntegrationBinding。 我应该使用什么?何时使用?
A: 当您希望使用 MSMQ 作为两个 WCF 应用程序之间排队通信的传输方式时,请使用 NetMsmqBinding。 使用现有 MSMQ 应用程序与新的 WCF 应用程序通信时,请使用MsmqIntegrationBinding。
问: 是否需要升级 MSMQ 才能使用 NetMsmqBinding 和 MsmqIntegration 绑定?
答: 不是。 这两个绑定都适用于 Windows XP 和 Windows Server 2003 上的 MSMQ 3.0。 升级到 Windows Vista 中的 MSMQ 4.0 时,绑定的某些功能将变为可用。
问:在 MSMQ 4.0 中,NetMsmqBinding 和 MsmqIntegrationBinding 绑定有哪些功能可用,而在 MSMQ 3.0 中不可用?
答: 以下功能在 MSMQ 4.0 中可用,但在 MSMQ 3.0 中不可用:
自定义死信队列仅支持在 MSMQ 4.0 上。
MSMQ 3.0 和 4.0 以不同的方式处理有害消息。
只有 MSMQ 4.0 支持远程事务处理读取。
问: 是否可以在排队通信的一端使用 MSMQ 3.0,另一端是否可以使用 MSMQ 4.0?
答: 是的。
问: 我想将现有的 MSMQ 应用程序与新的 WCF 客户端或服务器集成。 是否需要升级整个 MSMQ 基础结构?
答: 不是。 你不必在任一端升级到 MSMQ 4.0。
Troubleshooting
本部分包含最常见故障排除问题的解答。 发行说明中还介绍了已知限制的一些问题。
问: 我尝试使用专用队列,我收到以下异常: System.InvalidOperationExceptionURL 无效。 队列的 URL 不能包含“$”字符。 使用 net.msmq://machine/private/queueName 中的语法解决专用队列问题。
A: 检查配置和代码中的队列统一资源标识符(URI)。 请勿在 URI 中使用“$”字符。 例如,若要解决名为 OrdersQueue 的专用队列,请将 URI 指定为 net.msmq://localhost/private/ordersQueue。
问: 调用 ServiceHost.Open() 等待的应用程序将引发以下异常:System.ArgumentException基址不能包含 URI 查询字符串。 为什么?
答: 核对配置文件和代码中的队列 URI。 虽然 MSMQ 队列支持使用“?”字符,但 URI 将此字符解释为字符串查询的开头。 若要避免此问题,请使用不包含“?”字符的队列名称。
问: 我的发送成功,但没有在接收方上调用任何服务作业的操作。 为什么?
A: 若要确定答案,请查看以下检查列表:
检查事务处理队列的要求是否与指定的保障条件兼容。 请注意以下原则:
可以将使用“恰好一次”保证的持久消息(数据报和会话)仅发送到事务队列。
只有在具备“恰好一次”保证的情况下才能发送会话。
事务需要从事务队列接收会话中的消息。
只能向非事务性队列发送或接收易失性或持久性消息(仅限数据报),且不提供保证(ExactlyOnce =
false)。
检查死信队列。 如果在此处找到这些消息,请确定它们未送达的原因。
检查传出队列是否有连接或寻址问题。
问: 我指定了自定义死信队列,但在启动发送方应用程序时,我遇到一个异常,即找不到死信队列,或者发送应用程序无权访问死信队列。 这是什么原因?
答: 自定义死信队列的 URI 必须在第一个段中包含“localhost”或计算机名称,例如 net.msmq://localhost/private/myAppdead-letter-queue。
问: 是否始终需要定义自定义死信队列,还是存在默认死信队列?
答:如果保证“恰好一次”(ExactlyOnce = true),并且如果未指定自定义死信队列,那么默认值为系统范围的事务死信队列。
如果保证为 none(ExactlyOnce = false),则默认不使用死信队列功能。
问: 我的服务在 SvcHost.Open 调用时抛出异常,消息为“ListenerFactory 无法满足 EndpointListener 的要求”。 为什么?
答: 检查服务合同。 你可能忘记在所有服务操作上添加“IsOneWay=true”。 队列仅支持单向服务操作。
问: 队列中有消息,但没有调用服务操作。 遇到了什么问题?
答: 确定服务主机是否出现故障。 可以通过查看跟踪或实现 IErrorHandler来检查。 如果检测到病毒消息,则服务主机默认出错。
问: 队列中有消息,但我托管在 Web 上的队列服务未被激活。 为什么?
A: 最常见的原因是权限。
确保
NetMsmqActivator进程正在运行,并为进程标识NetMsmqActivator提供对队列的读取和查找权限。如果
NetMsmqActivator在远程计算机上监视队列,请确保NetMsmqActivator不会在受限令牌下运行。 若要运行NetMsmqActivator不受限制的令牌,请执行以下操作:sc sidtype NetMsmqActivator unrestricted
有关非安全性相关的 Web 主机问题,请参阅: Web 托管排队应用程序。
问: 访问会话的最简单方法是什么?
答: 在与会话中最后一条消息对应的操作上设置 AutoComplete=true,并在所有剩余的服务操作上设置 AutoComplete=false。
问: 为什么我的服务在从包含排队会话消息和排队数据报消息的队列中读取时引发 ProtocolException ?
A: 排队会话消息和排队数据报消息的组成方式存在根本差异。 因此,预期读取排队会话消息的服务无法接收排队的数据报消息,而预期读取排队数据报消息的服务无法接收会话消息。 尝试从同一队列读取这两种类型的消息会引发以下异常:
System.ServiceModel.MsmqPoisonMessageException: The transport channel detected a poison message. This occurred because the message exceeded the maximum number of delivery attempts or because the channel detected a fundamental problem with the message. The inner exception may contain additional information.
---> System.ServiceModel.ProtocolException: An incoming MSMQ message contained invalid or unexpected .NET Message Framing information in its body. The message cannot be received. Ensure that the sender is using a compatible service contract with a matching SessionMode.
如果应用程序从同一台计算机发送排队会话消息和排队数据报消息,则系统死信队列以及任何自定义死信队列尤其容易出现此问题。 如果无法成功发送消息,则会将其移动到死信队列。 在这些情况下,可以在死信队列中同时包含会话和数据报消息。 从队列读取时,在运行时无法分隔这两种类型的消息,因此应用程序不应同时从同一台计算机发送排队的会话消息和排队的数据报消息。
MSMQ 集成:特定故障排除
问: 当我发送消息或打开服务主机时,我收到一个指示协议错误的错误。 为什么?
一个: 使用 MSMQ 集成绑定时,必须使用 msmq.formatname 方案。 例如,msmq.formatname:DIRECT=OS:.\private$\OrdersQueue。 但是,当指定自定义死信队列时,必须使用 net.msmq 协议。
问: 当我使用公共或专用格式名称并在 Windows Vista 上打开服务主机时,我会收到错误。 为什么?
A: Windows Vista 上的 WCF 集成通道会检查是否可以为主应用程序队列打开子队列来处理毒性消息。 子队列名称派生自传递给侦听器的 msmq.formatname URI。 MSMQ 中的子队列名称只能是直接格式名称。 因此,你会看到错误。 将队列 URI 更改为直接格式名称。
问: 从 MSMQ 应用程序接收消息时,该消息位于队列中,接收 WCF 应用程序不会读取消息。 为什么?
A: 检查消息是否有消息体。 如果消息没有正文,MSMQ 集成通道将忽略该消息。 实现 IErrorHandler 以接收异常通知并检查日志跟踪。
与安全相关的故障排除
问: 当我在工作组模式下运行使用默认绑定的示例时,消息似乎已发送,但接收方从未收到消息。
A: 默认情况下,使用需要 Active Directory 目录服务的 MSMQ 内部证书对消息进行签名。 在工作组模式下,由于 Active Directory 不可用,因此对消息进行签名失败。 因此,消息进入死信队列,并被指示其失败原因,例如“签名错误”。
解决方法是关闭安全性。 这是通过设置 Mode = None 使其在工作组模式下工作来完成的。
另一种方法是从MsmqTransportSecurity属性获取Transport并将其设置为Certificate,然后设置客户端证书。
然而,另一种解决方法是安装具有 Active Directory 集成功能的 MSMQ。
问: 当我将 Active Directory 中默认绑定(传输安全性已打开)的消息发送到队列时,会收到“找不到内部证书”消息。 如何修复此问题?
A: 这意味着需要更新发件人在 Active Directory 中的证书。 为此,请打开 控制面板、 管理工具、 计算机管理、右键单击 MSMQ,然后选择“ 属性”。 选择“ 用户证书 ”选项卡,然后单击“ 续订 ”按钮。
问: 当我使用 Certificate 并指定要使用的证书发送消息时,会收到“证书无效”消息。 如何修复此问题?
A: 您不能在证书模式下使用本地计算机证书存储。 必须使用证书管理单元将证书从计算机证书存储复制到当前用户存储。 若要获取证书管理单元,请执行以下操作:
单击“ 开始”,选择“ 运行”,键入
mmc,然后单击“ 确定”。在 Microsoft 管理控制台中,打开 “文件” 菜单,然后选择 “添加/删除管理单元”。
在 “添加/删除管理单元 ”对话框中,单击“ 添加 ”按钮。
在添加独立管理单元对话框中,选择“证书”,然后单击添加。
在“ 证书 ”管理单元对话框中,选择 “我的用户帐户”, 然后单击“ 完成”。
接下来,使用前面的步骤添加第二个证书管理单元,但这次选择 计算机帐户 并单击“ 下一步”。
选择 “本地计算机 ”,然后单击“ 完成”。 现在可以将证书从计算机证书存储拖放到当前用户存储。
问: 当我的服务在工作组模式下从另一台计算机上的队列中读取时,我会收到“拒绝访问”异常。
一个: 在工作组模式下,要使远程应用程序能够访问队列,应用程序必须具有访问队列的权限。 将“匿名登录名”添加到队列的访问控制列表(ACL),并向其授予读取权限。
问: 当网络服务客户端(或任何没有域帐户的客户端)发送排队消息时,发送会失败,证书无效。 如何修复此问题?
A: 检查绑定配置。 默认绑定已启用 MSMQ 传输安全性以对消息进行签名。 关掉。
远程事务处理接收
问: 计算机 A 上有一个队列,同时有一个 WCF 服务从计算机 B 上的队列中读取消息(远程事务处理接收方案),但消息未被读取。 跟踪信息显示接收时失败,并出现消息“无法导入事务”。我能做些什么来解决这个问题?
答: 有三个可能的原因:
如果处于域模式,远程事务接收需要 Microsoft 分布式事务处理协调器(MSDTC)的网络访问。 可以使用 “添加/删除组件”启用此功能。
检查身份验证模式以与事务管理器通信。 如果处于工作组模式,则必须选择“不需要身份验证”。 如果处于域模式,则必须选择“需要相互身份验证”。
请确保 MSDTC 位于 Internet 连接防火墙 设置中的例外列表中。
确保使用的是 Windows Vista。 Windows Vista 上的 MSMQ 支持远程事务读取。 早期 Windows 版本的 MSMQ 不支持远程事务读取。
问: 当从队列中读取的服务是网络服务时,例如在 Web 主机中,为什么从队列读取时会出现访问被拒绝异常?
A: 必须将网络服务的读取权限添加到队列 ACL,以确保网络服务可以从队列中读取。
问: 是否可以使用 MSMQ 激活服务根据远程计算机上的队列中的消息激活应用程序?
答: 是的。 为此,必须将 MSMQ 激活服务配置为作为网络服务运行,并将网络服务访问权限添加到远程计算机上的队列。
使用启用了 ReceiveContext 的自定义 MSMQ 绑定
使用启用ReceiveContext的自定义 MSMQ 绑定时,由于本机 MSMQ 不支持异步ReceiveContext接收的 I/O 完成,传入消息的处理会使用线程池中的线程。 这是因为处理此类消息需要使用内部事务,而ReceiveContext MSMQ 不支持异步处理。 若要解决此问题,可以在终结点添加 SynchronousReceiveBehavior 以强制同步处理,或者将 MaxPendingReceives 设置为 1。