Недавно я столкнулся с проблемой асинхронных операций в MSMQ.В .NET 2.0, 3.0 и 3.5, если имеется ожидающее асинхронное получение, и очередь удаляется, вызывается обратный вызов, и при вызове EndReceive возникает исключение.
В .NET 4.0, обратный вызовникогда не вызывается, но исключение может быть перехвачено обработчиком события AppDomain.UnhandledException.При запуске в отладчике приложение просто завершает работу без уведомления Visual Studio о возникновении исключения.
Этот код выполняется в 64-разрядной версии Windows 7 Professional.Тем не менее, поведение одинаково, нацелено ли приложение на x86 или x64. (Редактировать: это поведение также проверялось в 32-разрядной версии XP SP3 - это ошибка платформы, не связанная с ОС)
Я предполагаю, что это новое поведение связано с.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, кажется), и охотясь через две разные сборки System.Messaging с помощью Reflector, я наконец нашел проблему.
В сборке 2.0 используются некоторые блоки try / catchв методе MessageQueue.AsynchronousRequest.RaiseCompletionEvent для перехвата исключений и сохранения кода ошибки, чтобы исключение могло быть вызвано при вызове .EndReceive ().Однако в сборке 4.0 эти попытки / перехваты пропали, поэтому при возникновении исключения процесс должен завершиться, поскольку они не перехвачены в фоновом потоке.
К сожалению, это не помогает мне решить проблему,Я рассматриваю возможность переключения на синхронный прием, но мне понравилась идея использовать для этого порты завершения ввода / вывода.