在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();
其中Global.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();
}
答案 0 :(得分:1)
您的说明和this thread表明了时间问题。我不经常创建MessageQueue
对象(可能只有一次)并且Global.getOutputQueue(mode)
返回一个缓存版本,似乎可能会解决这个问题。
编辑:进一步的细节表明你有相反的问题。我建议封装对消息队列的访问,捕获此异常并在发生异常时重新创建队列。因此,用以下内容替换对Global.getOutputQueue(mode).GetAllMessages()的调用:
public void getAllOutputQueueMessages()
{
try
{
return queue_.GetAllMessages();
}
catch (Exception)
{
queue_ = OpenQueue();
return queue_.GetAllMessages();
}
}
您会注意到我没有保留您的mode
功能,但您明白了。当然,您必须为您对队列进行的其他调用复制此模式,但仅限于您所创建的模式(而不是整个队列接口)。
答案 1 :(得分:1)
这是一个老线程,但谷歌把我带到这里,所以我将添加我的发现。
我同意用户的意见:这是一个时间问题。
创建消息队列后,它不会立即可用。
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);
}
}
因为它可能会抛出一个异常,说明您尝试创建的队列已经存在。
-edit :(抱歉,我没有这个新信息的相关链接)
我读到新创建的MessageQueue将在MessageQueue.Exists(QueuePath)上返回false,直到它收到至少一条消息。
保持这一点以及我提到的早期要点让我的代码可靠地运行。