1

I have a legacy Windows service running on Server 2008 that reads messages from a Transactional MSMQ Queue. This is not configured as a WCF service.

We are wanting to improve the handling of failed and poison messages in code (C# 4.0) by catching custom exceptions and sending the related message to a separate 'failed' or 'poison' queue depending upon the type of exception thrown.

I can't get the Catch code to send the message to the separate queue - it disappears from the original queue (as desired!) but doesn't show up in the 'failed' queue.

For testing all of the queues have no Authentication required and permissions are set to allow Everyone to do everything.

Clearly something is missing or wrong and I suspect it is transaction related, but I can't see it. Or perhaps this is not possible the way I am trying to do it ?

Any guidance / suggestions appreciated!

Our simplified PeekCompleted Event code:

 private void MessageReceived(object sender, PeekCompletedEventArgs e)
    {

        using (TransactionScope txnScope = new TransactionScope())
        {
            MyMessageType currentMessage = null;
            MessageQueue q = ((MessageQueue)sender);
            try
            {
                Message queueMessage = q.EndPeek(e.AsyncResult);
                currentMessage = (FormMessage)queueMessage.Body;
                Processor distributor = new Processor();

                Processor.Process(currentMessage); // this will throw if need be

                q.ReceiveById(e.Message.Id);
                txnScope.Complete();
                q.BeginPeek();
            }
            catch (MyCustomException ex)
            {
                string qname = ".\private$\failed";
                if (!MessageQueue.Exists(qname)){
                     MessageQueue.Create(qname , true);
                }
                MessageQueue fq = new MessageQueue(qname){
                    Formatter = new BinaryMessageFormatter()
                };
                System.Messaging.Message message2 = new System.Messaging.Message{
                    Formatter = new BinaryMessageFormatter(),
                    Body = currentMessage,
                    Label = "My Failed Message";
                };
                fq.Send(message2);           //send to failed queue
                q.ReceiveById(e.Message.Id); //off of original queue
                txnScope.Complete();         // complete the trx
                _queue.BeginPeek();          // next or wait
            }
            //other catches handle any cases where we want to tnxScope.Dispose()

EDIT : October 8, 2013

Hugh's answer below got us on the right track. Inside the Catch block the Failed Queue was already created as transactional

MessageQueue.Create(qname , true);

but the Send needed a TransactionType parameter

fq.Send(message2,MessageQueueTransactionType.Single);

That did the trick. Thanks Hugh!

4

1 回答 1

0

如果消息从您的原始队列中消失,那么这意味着您的代码正在到达第二个 scope.Complete() (在您的 catch 块中)。

这意味着问题与您发送到错误队列有关。

我建议您需要将队列创建为事务性的,因为您是从范围内发送的。

MessageQueue fq = new MessageQueue(qname, true){
    Formatter = new BinaryMessageFormatter()
};

然后你需要做一个事务性发送:

fq.Send(message2, Transaction.Current);

看看这是否有效。

于 2013-10-08T09:17:42.873 回答