engg
engg

Reputation: 341

sporadic error while getting all messages in Windows messagequeue

In C# ASP.NET 3.5 web application running on Windows Server 2003, I get the following error once in a while:

"Object reference not set to an instance of an object.:   at System.Messaging.Interop.MessagePropertyVariants.Unlock()
   at System.Messaging.Message.Unlock()
   at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
   at System.Messaging.MessageEnumerator.get_Current()
   at System.Messaging.MessageQueue.GetAllMessages()".

The line of code that throws this error is:

Message[] msgs = Global.getOutputQueue(mode).GetAllMessages();

where Global.getOutputQueue(mode) gives the messagequeue I want to get messages from.

Update:

 Global.getPool(mode).WaitOne();
 commonClass.log(-1, "Acquired pool: " + mode, "Report ID: " + unique_report_id);
            ............../* some code /
            ..............
                        lock(getLock(mode))
                        {
                            bool yet_to_get = true;
                            int num_retry = 0;
                            do
                            {
                                try
                                {
                                    msgs = Global.getOutputQueue(mode).GetAllMessages();
                                    yet_to_get = false;
                                }
                                catch
                                {
                                    Global.setOutputQueue(mode);
                                    msgs = Global.getOutputQueue(mode).GetAllMessages();
                                    yet_to_get = false;
                                }
                                ++num_retry;
                            }
                            while (yet_to_get && num_retry < 2);
                        }
... / some code*/
....
finally
            {
                commonClass.log(-1, "Released pool: " + mode, "Report ID: " + unique_report_id);
                Global.getPool(mode).Release();
            }
 

Upvotes: 0

Views: 950

Answers (2)

tessi
tessi

Reputation: 179

This is an old thread, but google brought me here so I shall add my findings.

I agree with user: tallseth that this is a timing issue.

After the message queue is created it is not instantly available.

        try
        {
            return _queue.GetAllMessages().Length;
        }
        catch (Exception)
        {
            System.Threading.Thread.Sleep(4000);
            return _queue.GetAllMessages().Length;
        }

try adding a pause if you catch an exception when accessing a queue which you know has been created.

On a related note

_logQueuePath = logQueuePath.StartsWith(@".\") ? logQueuePath : @".\" + logQueuePath;
 _queue = new MessageQueue(_logQueuePath);
 MessageQueue.Create(_logQueuePath);
 bool exists = MessageQueue.Exists(_logQueuePath); 

running the MessageQueue.Exists(string nameofQ); method immediately after creating the queue will return false. So be careful when calling code such as:

        public void CreateQueue()
    {
        if (!MessageQueue.Exists(_logQueuePath))
        {
            MessageQueue.Create(_logQueuePath);
        }
    }

As it is likely to throw an exception stating that the queue you are trying to create already exists.

-edit: (Sorry I don't have the relevant link for this new info)

I read that a newly created MessageQueue will return false on MessageQueue.Exists(QueuePath)until it has received at least one message.

Keeping this and the earlier points i mentioned in mind has gotten my code running reliably.

Upvotes: 1

tallseth
tallseth

Reputation: 3665

Your description and this thread suggests a timing issue. I would create the MessageQueue object infrequently (maybe only once) and have Global.getOutputQueue(mode) return a cached version, seems likely to get around this.

EDIT: Further details suggest you have the opposite problem. I suggest encapsulating access to the message queue, catching this exception and recreating the queue if that exception occurs. So, replace the call to Global.getOutputQueue(mode).GetAllMessages() with something like this:

public void getAllOutputQueueMessages()
{
    try
    {
        return queue_.GetAllMessages();
    }
    catch (Exception)
    {
        queue_ = OpenQueue();
        return queue_.GetAllMessages();
    }
}

You'll notice I did not preserve your mode functionality, but you get the idea. Of course, you have to duplicate this pattern for other calls you make to the queue, but only for the ones you make (not the whole queue interface).

Upvotes: 1

Related Questions