【问题标题】:sporadic error while getting all messages in Windows messagequeue获取 Windows 消息队列中的所有消息时出现零星错误
【发布时间】:2012-07-06 03:16:03
【问题描述】:

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

【问题讨论】:

    标签: c# asp.net windows message-queue system.messaging


    【解决方案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 功能,但您明白了。当然,您必须为对队列进行的其他调用复制此模式,但仅限于您进行的调用(而不是整个队列接口)。

    【讨论】:

    • 谢谢 tallseth。 MessageQueue 对象已在 Application_Start(Object sender, EventArgs e) 中创建。 Global.getOutputQueue(mode) 方法只是返回它。我错过了什么吗?谢谢。 public static MessageQueue getOutputQueue(char mode) { return (mode == 'd') ?输出Qd:输出Qw; }
    • 听起来您可能有相反的问题,队列的句柄陈旧。如果可能,不要将队列返回给您的调用代码,而是代理您需要的队列上的方法。然后捕获此异常,并通过重新创建队列来处理它,然后重试。但请确保不要递归,如果出现严重错误,您不希望无限循环。
    【解决方案2】:

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

    我同意用户: 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);
            }
        }
    

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-17
      • 2017-06-14
      • 1970-01-01
      • 2013-12-13
      • 2018-08-10
      • 1970-01-01
      • 2013-07-18
      • 2012-03-16
      相关资源
      最近更新 更多