0

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();
            }
 
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
engg
  • 343
  • 1
  • 4
  • 12

2 Answers2

1

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).

tallseth
  • 3,635
  • 1
  • 23
  • 24
  • Thanks tallseth. The MessageQueue object has already been created in Application_Start(Object sender, EventArgs e). Global.getOutputQueue(mode) method just returns it. Am I missing something? Thanks. public static MessageQueue getOutputQueue(char mode) { return (mode == 'd') ? outputQd : outputQw; } – engg Jul 05 '12 at 22:22
  • Sounds like you might have the opposite problem, a stale handle to a queue. If possible, instead of returning the queue to your calling code, proxy the methods on the queue that you need. Then catch this exception, and handle it by recreating the queue, and trying again. Make sure not to recurse though, you don't want an infinite loop if something goes very wrong. – tallseth Jul 05 '12 at 22:30
1

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.

tessi
  • 179
  • 1
  • 4