2012-04-17 2 views
3

私はBeginReceive()、EndReceive()、およびReceivedCompletedイベントを使用している非同期APIサポートを使用してMSMQから読み取っているコードを持っています。基本的なパターンは、新しいメッセージを待っている(私が見ることができる問題は保留BeginReceiveは(常に存在することであるMessageQueue.ReceiveCompleted Event ...MSMQリスナを正しくクリーンアップする方法は?

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(); 
} 

から取られた)である、と.NETのドキュメントを読んで、そこを通って表示されません。

メッセージを受信せずにEndReceive()を呼び出すと、メッセージが利用可能になるまで呼び出しがブロックされます。 )は、EnableConnectionCacheがfalseに設定されていない限り、MSMQ(したがって保留中のリスナー)の基になるハンドルをクリーンアップしません。そうでない場合、ハンドルはキャッシュされ、クリーンアップされません閉じるための呼び出しで。私はこれを行うことができますが、理想的にはキャッシングを使いたいと思います。

私が見ることのできる唯一の他のオプションは、キャッシングを有効にして静的メソッドMessageQueue.ClearConnectionCache()を呼び出すことでした。おそらくアプリケーションドメイン全体であり、したがって、閉じようとしているキューに関係のないキューに影響します。

補遺: 追加オプション(MessageQueue.Close()から)、彼らが共有される可能性がありますので...

閉じるには、常に読み取りを解放し、キュー、 にハンドルを書き込みません。 のいずれかの手順を実行して、Closeが読み取りと書き込みのハンドルをキューに解放するようにすることができます。

排他アクセスでMessageQueueを作成します。これを行うには、 MessageQueue(String、Boolean)またはMessageQueue(String、Boolean、Boolean、 Boolean)コンストラクターを呼び出し、sharedModeDenyReceiveパラメーターを に設定します。

接続キャッシュを無効にしてMessageQueueを作成します。これを行うには、 MessageQueue(String、Boolean、Boolean)コンストラクターを呼び出し、 enableConnectionCacheパラメーターをfalseに設定します。

接続キャッシュを無効にします。これを行うには、EnableConnectionCache プロパティをfalseに設定します。

したがってドキュメントからAPIの私の第一印象は、(BeginReceive/EndReceiveを使用した場合)キャッシングがまたはあなたがキューへの排他的アクセスを持って使用されていない場合を除き、あなたが適切にキューを終了することができないということです。

答えて

0

でここを見てください。これは、呼び出し元にすぐに戻る非同期呼び出しですが、潜在的に非常に長い存続期間を持つ可能性のある未処理の非同期操作が発生します。

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

1つの解決方法は、BeginReceive(タイムアウト)を使用することです。これにより、メッセージがない場合でもReceiveCompletedイベントが発生します。その時点で、クローズが要求されていることを確認するフラグをテストし、クリーンアップが正常に進行するようにします。すなわち、メッセージ待ち行列を閉じるための外部要求は、待機しなければならない。 ReceiveCompletedイベントが通知するWaitHandleを返します。したがって、パターンは数秒(理想的には1秒または2秒)の短いBeginReceive()タイムアウトで最も効果的です。

+0

ReceivedCompleted()呼び出しの理由がEndReceive()の呼び出しとタイムアウト例外のキャッチ以外のタイムアウトであることを検出する方法はありますか? – NTDLS