非同期 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 は、共有されている可能性があるため、キューへの読み取りハンドルと書き込みハンドルを常に解放するとは限りません。次のいずれかの手順を実行して、Close が読み取りハンドルと書き込みハンドルをキューに解放することを確認できます。
排他アクセスで MessageQueue を作成します。これを行うには、MessageQueue(String, Boolean) または MessageQueue(String, Boolean, Boolean) コンストラクターを呼び出し、sharedModeDenyReceive パラメーターを true に設定します。
接続キャッシュを無効にして MessageQueue を作成します。これを行うには、MessageQueue(String, Boolean, Boolean) コンストラクターを呼び出し、enableConnectionCache パラメーターを false に設定します。
接続キャッシュを無効にします。これを行うには、EnableConnectionCache プロパティを false に設定します。
したがって、ドキュメントからの API の私の最初の印象は、キャッシュが使用されていないか、キューへの排他的アクセスがない限り、(BeginReceive/EndReceive を使用している場合) キューを適切に終了できないということです。