在 .NET 4.0 中,回调函数不会被调用,但是异常可以被 AppDomain.UnhandledException 事件处理程序捕获。当在调试器中运行时,应用程序将简单终止,Visual Studio 不提供任何有关异常发生的通知。
这段代码在 Windows 7 Professional 64 位上执行,但无论应用程序针对 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已经不存在了,因此当发生异常时,进程必须终止,因为它们在后台线程中未被捕获。
不幸的是,这并没有帮助我解决问题。 我正在考虑切换到同步接收,但我喜欢利用I/O完成端口的想法。