MSMQ 異步異常行為 - .NET 4.0 與 .NET 2.0 (MSMQ asynchronous exception behavior - .NET 4.0 vs .NET 2.0)


問題描述

MSMQ 異步異常行為 ‑ .NET 4.0 與 .NET 2.0 (MSMQ asynchronous exception behavior ‑ .NET 4.0 vs .NET 2.0)

我最近在 MSMQ 中遇到了異步操作的問題。在 .NET 2.0、3.0 和 3.5 中,如果存在掛起的異步接收,並且隊列被刪除,則調用回調並在調用 EndReceive 時引發異常。

在 .NET 4.0 中,回調永遠不會被調用,但異常可以被 AppDomain.UnhandledException 事件處理程序捕獲。在調試器中運行時,應用程序將簡單地終止,而不會從 Visual Studio 發出發生異常的通知。

此代碼在 64 位 Windows 7 Professional 上執行。但是,無論應用程序是針對 x86 還是 x64,行為都是相同的。(編輯:在 XP SP3 32 位上也驗證了這種行為 ‑ 這似乎是一個框架錯誤,與操作系統無關)

我假設這種新行為與 .NET 4.0 作為一個全新的運行時有關。我不確定此時該做什麼,但基本上我希望恢復 .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 源可用於 4.0 但不適用於 2.0/3.5,它似乎),並用Reflector翻遍了兩個不同的System.Messaging程序集,終於找到了問題所在。

在2.0程序集中,MessageQueue.AsynchronousRequest.RaiseCompletionEvent方法中使用了一些try/catch塊來捕獲異常和存儲錯誤代碼,以便在調用 .EndReceive() 時引發異常。但是,在 4.0 程序集中,這些 try/catch 消失了,因此當發生異常時,進程必須終止,因為它們沒有被後台線程捕獲。

不幸的是,這並不能幫助我修復問題。我正在考慮切換到同步接收,


## 參考解法 #### 方法 1:

Well, I am going to answer this and accept it, since I think it's the best answer for the near future. It could be months (or more) before there is a proper solution.

As mentioned above, I filed a bug report on Microsoft Connect, so it is pretty much up to them to revert the behavior to how it worked in CLR 2.0.

Microsoft Connect: http://connect.microsoft.com/VisualStudio/feedback/details/626177/messagequeue‑beginreceive‑asynchronous‑exception‑behavior

As far as how this affects my application, I am not willing to switch to a synchronous Receive method, as that would consume all of the available worker threads on the thread pool. My application frequently creates and removes a lot of queues, and this issue arose when a command to remove a queue was issued, but an outstanding read operation was pending. Instead, I will just mark that a queue needs to be removed, and once a safe period of time has elapsed (two times the BeginReceive timeout, for instance), I will actually remove the queue.

Or switch to a different queuing system than MSMQ, though I've been happy with it so far.

(by Brad NabholzBrad Nabholz)

參考文件

  1. MSMQ asynchronous exception behavior ‑ .NET 4.0 vs .NET 2.0 (CC BY‑SA 3.0/4.0)

#.net-4.0 #Callback #msmq #Exception #asynchronous






相關問題

SendKeys.Send NullReferenceException (SendKeys.Send NullReferenceException)

訪問 MarkupExtension.ProvideValue 中的構造函數參數 (Access to a constructor parameter within MarkupExtension.ProvideValue)

調試時使用 WorkflowInvoker 發生瘋狂的內存洩漏 (Crazy memory leak with WorkflowInvoker while debugging)

為跨域的 .NET Framework 靜默安裝創建部署應用程序? (Creating a deployment application for .NET Framework silent install across domain?)

Windows 窗體關閉後刪除的窗體數據 (Form data erased after Windows form is closed)

如何從 php wordpress 服務器呈現 aspx 頁面 (How to render an aspx page from a php wordpress server)

嘗試通過方法“System.Web.Helpers.Json.Decode(System.String)”訪問字段“System.Web.Helpers.Json._serializer”失敗 (Attempt by method 'System.Web.Helpers.Json.Decode(System.String)' to access field 'System.Web.Helpers.Json._serializer' failed)

如何使用 Windows 資源管理器顯示項目和詳細信息展開/折疊 (How to Display Items and Details with Windows Explorer Expand/Collapse)

在 C# 中通過反射訪問屬性 (Accessing attribute via reflection in C#)

連續輸入時不要引發 TextChanged (Don't raise TextChanged while continuous typing)

MSMQ 異步異常行為 - .NET 4.0 與 .NET 2.0 (MSMQ asynchronous exception behavior - .NET 4.0 vs .NET 2.0)

多線程 WMI 調用 - 如何最好地處理這個? (Multithreading WMI calls - how best to handle this?)







留言討論