3

非同期 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 を使用している場合) キューを適切に終了できないということです。

4

2 に答える 2

0

問題の核心は、MSDN のMessageQueue.ReceiveCompleted Eventのサンプル C# がパラメーターなしで BeginReceive() を使用していることです。これは呼び出し元にすぐに戻る非同期呼び出しですが、非常に長い有効期間を持つ可能性のある未処理の非同期操作が発生します。

MessageQueue で Close() を呼び出そうとすると、この未処理の非同期操作により、MessageQueue の適切な解放が妨げられます。

1 つの解決策は、BeginReceive(Timeout); を使用することです。これにより、メッセージがない場合でも ReceiveCompleted イベントが発生します。この時点でフラグをテストして、クローズが要求されていることを確認し、クリーンアップを正常に進行させることができます。つまり、メッセージ キューを閉じるための外部要求は、ReceiveCompleted イベントが通知する WaitHandle などで待機する必要があります。したがって、このパターンは、数秒 (理想的には 1 秒または 2 秒) の短い BeginReceive() タイムアウトで最適に機能します。

于 2015-08-19T10:58:33.720 に答える
0

Event Driven consumerをご覧ください。2018 年 12 月 19 日の時点で、この URL は 404 を返します。

于 2012-04-18T16:38:44.977 に答える