2010-11-29 14 views
3

最近、MSMQで非同期操作に関する問題が発生しました。 .NET 2.0,3.0および3.5では、保留中の非同期受信があり、キューが削除された場合、コールバックが呼び出され、EndReceiveの呼び出し時に例外がスローされます。MSMQ非同期例外動作 - .NET 4.0と.NET 2.0

.NET 4.0では、コールバックは呼び出されませんが、例外はAppDomain.UnhandledExceptionイベントハンドラによってキャッチされます。デバッガで実行中の場合、アプリケーションはVisual Studioからの通知なしで終了し、例外が発生します。

このコードは、Windows 7 Professional、64-bitで実行されています。ただし、アプリケーションがx86またはx64をターゲットにしている場合でも、動作は同じです。 (編集:XP SP3 32ビットでこの動作が確認されています。これはOS関連ではなくフレームワークのバグです)

私は、この新しい動作が完全に新しいランタイム。この時点で何をすべきかはわかりませんが、基本的に.NET 4.0ランタイムをターゲットにしながら、.NET 4.0以前の動作を元に戻すことを目指しています。どんな助けやアドバイスも大歓迎です。ここでは、問題を再現するサンプルコードは、次のとおりです。

class Program 
{ 
    static void Main(string[] args) 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 
     string path = @".\private$\mytestqueue"; 
     // Create queue only if it doesn't already exist. 
     var queue = MessageQueue.Exists(path) ? new MessageQueue(path) : MessageQueue.Create(path); 
     queue.BeginReceive(TimeSpan.FromSeconds(15), queue, new AsyncCallback(ReceiveComplete)); 
     Thread.Sleep(5000); 
     MessageQueue.Delete(path); 
    } 

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     var mqEx = (MessageQueueException) e.ExceptionObject; 

     // .NET 4.0: 

     // "The queue does not exist or you do not have sufficient 
     // permissions to perform the operation." 
     Console.WriteLine(mqEx.Message); 
     // "QueueNotFound" 
     Console.WriteLine(mqEx.MessageQueueErrorCode); 
    } 

    static void ReceiveComplete(IAsyncResult ar) 
    { 
     // This callback is never invoked under .NET 4.0. 
     Console.WriteLine("Finishing Receive."); 
     var queue = (MessageQueue) ar.AsyncState; 
     try 
     { 
      queue.EndReceive(ar); 
     } 
     catch (MessageQueueException mqEx) 
     { 
      // .NET 2.0 through 3.5: 

      // "Queue handle can no longer be used to receive messages 
      // because the queue was deleted. The handle should be closed." 
      Console.WriteLine(mqEx.Message); 
      // "QueueDeleted" 
      Console.WriteLine(mqEx.MessageQueueErrorCode); 
     } 
    } 
} 

補遺:ソースをSystem.Messaging(ソースステッピングを使用しようとしてあまりにも多くの時間を過ごした後

は、2.0/3.5の4.0のために利用可能ではないです、それが現れます)、2つの異なるSystem.Messagingアセンブリを使ってReflectorで狩りをすると、私はついにこの問題を発見しました。

2.0アセンブリでは、MessageQueue.AsynchronousRequest.RaiseCompletionEventメソッドでいくつかのtry/catchブロックが使用され、例外をキャッチし、.EndReceive()が呼び出されたときに例外が発生するようにエラーコードを格納します。しかし、4.0アセンブリでは、これらのtry/catchがなくなり、例外が発生した場合、プロセスはバックグラウンドスレッドで捕捉されないので終了する必要があります。

残念ながら、これは問題を解決するのに役立ちません。同期受信に切り替えることを検討していますが、このためにI/O完了ポートを利用するというアイデアが気に入っています。

+2

あなたは確信してconnect.microsoft.comに投稿してください –

+0

@ハンス:これまで考えていたはずです!この問題を抱えていて、同じ問題がある人は、Connectのバグがあります:http://connect.microsoft.com/VisualStudio/feedback/details/626177/messagequeue-beginreceive-asynchronous-exception-behavior –

+0

今私はMicrosoftの接続サイトに移動するときに「ページが見つかりません」というメッセージが表示されます。誰でもこのバグの状態に関する情報を持っていますか? – DeCaf

答えて

2

私はこれが近い将来の最良の答えだと思うので、私はこれに答えてそれを受け入れるつもりです。適切な解決策が出るまでには数カ月(またはそれ以上)になる可能性があります。

上記のとおり、私はMicrosoft Connectのバグレポートを提出しました。そのため、CLR 2.0での動作を元に戻すことは、ほとんどの場合です。

マイクロソフト接続:http://connect.microsoft.com/VisualStudio/feedback/details/626177/messagequeue-beginreceive-asynchronous-exception-behavior

は限り、これは自分のアプリケーションにどのような影響を与えるかのように、私はそれがスレッドプールに利用できるワーカースレッドのすべてを消費することになると、同期受信方法に切り替えることを望んでいないよ 。私のアプリケーションでは、多くのキューが頻繁に作成され、削除されています。この問題は、キューを削除するコマンドが発行されたが、未処理の読み取り操作が保留中のときに発生しました。代わりに、キューを削除する必要があることをマークし、安全な期間が経過すると(たとえばBeginReceiveタイムアウトの2倍)、実際にキューを削除します。

これまでのところ、私はこれまで満足していましたが、MSMQとは異なるキューシステムに切り替えることもできます。

+2

... **頻繁に**作成して削除する** ** ** **たくさんのキュー?どうして? –