我有使用异步 API 支持从 MSMQ 读取的代码,即使用 BeginReceive()、EndReceive() 和 ReceivedCompleted 事件。基本模式是(取自MessageQueue.ReceiveCompleted Event ...
void StartListening()
{
_msgQ.ReceiveCompleted += ReceiveCompletedEventHandler(FooReceiveCompleted);
_msgQ.BeginReceive();
}
void FooReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult)
{
Message msg = _msgQ.EndReceive();
// Do stuff with message.
// Set up listening for next message.
_msgQ.BeginReceive();
}
void StopListening()
{
_msgQ.Close();
}
我可以看到的问题是,总是有一个待处理的 BeginReceive() 等待新消息,并且通过阅读 .Net 文档,似乎没有官方/推荐的方式来清理它以停止收听。
如果我在没有要接收的消息的情况下调用 EndReceive(),则调用会阻塞,直到有消息可用。或者,除非 EnableConnectionCache 设置为 false,否则 Close() 似乎不会清理 MSMQ 上的底层句柄(因此也不会清理挂起的侦听器),否则句柄会被缓存并且不会在调用关闭时被清理。我可以这样做,但理想情况下我想使用缓存。
我能看到的唯一其他选项是启用缓存,然后调用静态方法 MessageQueue.ClearConnectionCache() 可能是应用程序域范围,因此会影响与我尝试关闭的队列无关的队列。
附录:附加选项(来自MessageQueue.Close())...
关闭并不总是释放队列的读写句柄,因为它们可能是共享的。您可以采取以下任何步骤来确保 Close 将读取和写入句柄释放到队列:
创建具有独占访问权限的 MessageQueue。为此,请调用 MessageQueue(String, Boolean) 或 MessageQueue(String, Boolean, Boolean) 构造函数,并将 sharedModeDenyReceive 参数设置为 true。
创建禁用连接缓存的 MessageQueue。为此,请调用 MessageQueue(String, Boolean, Boolean) 构造函数并将 enableConnectionCache 参数设置为 false。
禁用连接缓存。为此,请将 EnableConnectionCache 属性设置为 false。
因此,我对文档 API 的第一印象是,除非不使用缓存或您对队列具有独占访问权限,否则您无法正确终止队列(使用 BeginReceive/EndReceive 时) 。