.NET assíncrona MSMQ
-
14-11-2019 - |
Pergunta
Eu não entendo onde isso vai dar errado.Basicamente, eu tenho um programa que recebe a partir de uma fila de mensagem e processa as mensagens.O programa pode ser interrompido a qualquer momento, caso em que o loop de mensagem de terminar o que está fazendo antes de sair do programa.Eu estou tentando fazer isso com o seguinte código:
private MessageQueue q;
private ManualResetEventSlim idle;
public void Start()
{
idle = new ManualResetEventSlim();
q.ReceiveCompleted += this.MessageQueue_ReceiveCompleted;
q.BeginReceive();
}
public void Stop()
{
this.q.Dispose();
this.idle.Wait();
}
private void MessageQueue_ReceiveCompleted(object sender,
ReceiveCompletedEventArgs e)
{
Message inMsg;
try
{
inMsg = e.Message;
}
catch (Exception ex)
{
this.idle.Set();
return;
}
// Handle message
this.q.BeginReceive();
}
Como é espero que aparente, o método Stop descarta a mensagem da fila e, em seguida, aguarda o ocioso esperar identificador para ser definido (o que deve ocorrer como um ReceiveCompleted evento será chamado quando descartados, mas o endereço de e.Mensagem de propriedade deve exceto).
No entanto, o loop de mensagem apenas continua!!!Eu tenho dispostos a fila de mensagens, mas, ainda assim, consegue ler e o manipulador de exceção não é invocada, ou seja, o ocioso.Aguarde linha de espera para sempre.
Meu entendimento é que eliminar uma fila de mensagens DEVE terminar qualquer curso recebe e invocar o evento, mas os endereços de e.Mensagem (ou q.EndReceive) deve lançar uma exceção.Este não é o caso?Se não, de que outra forma posso sair em segurança o meu ciclo de mensagem?
Obrigado
ATUALIZAÇÃO:
Aqui está um exemplo completo (assume a fila existe)
class Program
{
static MessageQueue mq;
static ManualResetEventSlim idleWH;
static void Main(string[] args)
{
idleWH = new ManualResetEventSlim();
Console.WriteLine("Opening...");
using (mq = new MessageQueue(@".\private$\test"))
{
mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(int) });
mq.ReceiveCompleted += mq_ReceiveCompleted;
for (int i = 0; i < 10000; ++i)
mq.Send(i);
Console.WriteLine("Begin Receive...");
mq.BeginReceive();
Console.WriteLine("Press ENTER to exit loop");
Console.ReadLine();
Console.WriteLine("Closing...");
mq.Close();
}
Console.WriteLine("Waiting...");
idleWH.Wait();
Console.WriteLine("Press ENTER (ex)");
//Console.ReadLine();
}
static void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
try
{
var msg = mq.EndReceive(e.AsyncResult);
Console.Title = msg.Body.ToString();
// Receive next message
mq.BeginReceive();
}
catch (Exception ex)
{
idleWH.Set();
return;
}
}
}
Solução 2
A única maneira que eu poderia começar este trabalho, com uma fila transacional.Qualquer não-transacional fila parece estar vulnerável a este.Não uma resposta, mas o melhor conselho que posso dar a qualquer pessoa que encontrar este.
Outras dicas
Não sei como você fez esse trabalho em todos os.Você deve chamada MessageQueue.EndReceive() no evento.Só que o método pode lançar a exceção.Rever o código de exemplo do MSDN para o ReceiveCompleted evento.E não pegar de Exceção, que só faz com que undiagnosable falha.Pegar a exceção específica que você começa quando você eliminar a fila, ObjectDisposedException.
private static volatile bool _shouldStop = false;
. . .
_shouldStop = true;
mq.Close();
. . .
try
{
var msg = mq.EndReceive(e.AsyncResult);
if ( _shouldStop)
{
idleWH.Set();
return;
}
mq.BeginReceive();
}
. . .