0

在 Windows Server 2003 上运行的 C# ASP.NET 3.5 Web 应用程序中,我偶尔会收到以下错误:

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

引发此错误的代码行是:

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

whereGlobal.getOutputQueue(mode)给出了我想从中获取消息的消息队列。

更新:

 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();
            }
 

4

2 回答 2

1

您的描述和此线程表明存在时间问题。我会MessageQueue不频繁地创建对象(可能只创建一次)并Global.getOutputQueue(mode)返回一个缓存版本,似乎可以解决这个问题。

编辑:进一步的细节表明你有相反的问题。我建议封装对消息队列的访问,捕获此异常并在发生异常时重新创建队列。因此,将对 Global.getOutputQueue(mode).GetAllMessages() 的调用替换为以下内容:

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

你会注意到我没有保留你的mode功能,但你明白了。当然,您必须为对队列进行的其他调用复制此模式,但仅限于您进行的调用(而不是整个队列接口)。

于 2012-07-05T18:13:23.797 回答
1

这是一个旧线程,但谷歌把我带到了这里,所以我将添加我的发现。

我同意用户: tallseth 这是一个时间问题。

创建消息队列后,它不会立即可用。

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

如果您在访问您知道已创建的队列时捕获异常,请尝试添加暂停。

在相关说明上

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

运行 MessageQueue.Exists(string nameofQ); 创建队列后立即方法将返回 false。所以调用代码时要小心,例如:

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

因为它可能会抛出一个异常,说明您尝试创建的队列已经存在。

-编辑:(抱歉,我没有此新信息的相关链接)

我读到一个新创建的 MessageQueue 将在 MessageQueue.Exists(QueuePath) 上返回 false,直到它收到至少一条消息。

牢记这一点和我之前提到的要点已经让我的代码可靠地运行。

于 2014-05-23T03:17:48.633 回答