在收到MSMQ消息期间处理Windows服务错误

时间:2013-09-30 05:35:04

标签: c# windows-services msmq

我有一个Windows服务,通过为MSMQ peekCompleted事件提供处理程序来监视私有MSMQ的消息,如下所示(在服务OnStart期间分配):

_queue.PeekCompleted += new PeekCompletedEventHandler(MessageReceived);

MessageReceived方法然后执行此操作(以下划线开头的变量在服务中全局声明):

 private void MessageReceived(object sender, PeekCompletedEventArgs e)
    {
        try
        {
            _handler = new MessageHandler(); //does the heavy lifting
            _queueMessage = _queue.EndPeek(e.AsyncResult);
            _queueMessage.Formatter = new BinaryMessageFormatter();
            _currentMessage = (MyMessageType)_queueMessage.Body;

            // we have the message so no matter what we want it off of the queue
            _queue.ReceiveById(_queueMessage.Id);

            // Message Handler is going to swallow everything here
            // messages are processed OK or moved to a 'failed' or 'poison' queue
            // there should be no uncaught exceptions
            _handler.Process(_currentMessage);

            //go wait again
            _queue.BeginPeek();
        }
        catch (Exception exception)
        {
           // here is question

        }
    }

问题:假设_handler吞下它生成/遇到的任何异常(并相应地处理它的消息)我不希望在这个try块中出现异常,但如果发生任何异常,我需要确保队列返回到正确的甚至我不知道异常可能发生在哪里。所以我只是

 _queue.ReceiveById(_queueMessage.Id);
 _queue.BeginPeek();

在catch块中,即使这两个语句中的任何一个可能已经被执行过了?我不能真的假设(咳咳)其中一个因某些未知原因而没有产生异常,这是异常的本质,是吗?

应如何处理?

1 个答案:

答案 0 :(得分:2)

不要处理它。如果您使队列成为事务性的,那么您可以在事务中包装ReceiveById调用。:

using (TransactionScope txnScope = new TransactionScope())
{
    _queue.ReceiveById(_queueMessage.Id);
    txnScope.Commit();
}

这将确保如果在提交之前抛出异常,则消息将保留在队列中。这仅在您接收的队列是本地队列时才有效。否则,您需要在所有涉及的机器上配置DTC。