简体   繁体   English

.NET异步MSMQ

[英].NET asynchronous MSMQ

I don't understand where this is going wrong. 我不知道哪里出了问题。 Basically, I have a program which receives from a message queue and processes the messages. 基本上,我有一个从消息队列接收并处理消息的程序。 The program can be stopped at any time, in which case the message loop finished what it is doing before the program exits. 程序可以随时停止,在这种情况下,消息循环会在程序退出之前完成其操作。 I'm trying to accomplish this with the following code: 我正在尝试通过以下代码完成此操作:

private MessageQueue q;
private ManualResetEventSlim idle;

public void Start()
{
    idle = new ManualResetEventSlim();
    q.ReceiveCompleted += this.MessageQueue_ReceiveCompleted;    
    q.BeginReceive();
}    

public void Stop()
{ 
    this.q.Dispose();
    this.idle.Wait();    
}

private void MessageQueue_ReceiveCompleted(object sender, 
    ReceiveCompletedEventArgs e)
{
    Message inMsg;
    try
    {
        inMsg = e.Message;
    }
    catch (Exception ex)
    {
        this.idle.Set();
        return;
    }

    // Handle message

    this.q.BeginReceive();
}

As is hopefully apparent, the Stop method disposes of the message queue, and then waits for the idle wait handle to be set (which should occur as an ReceiveCompleted event will be called when disposed, but the e.Message property should except). 显而易见,Stop方法将处理消息队列,然后等待设置空闲等待句柄(这应发生,因为在处理时将调用ReceiveCompleted事件,但e.Message属性应除外)。

However, the message loop just continues! 但是,消息循环只是继续! I've disposed the message queue, but it still manages to read from it and the exception handler is not invoked, meaning the idle.Wait line waits forever. 我已经放置了消息队列,但是它仍然设法从中读取消息,并且不调用异常处理程序,这意味着空闲。等待行永远等待。

My understanding is that disposing a message queue SHOULD end any pending receives and invoke the event, but the e.Message (or q.EndReceive) should throw an exception. 我的理解是,设置消息队列应该结束所有未决的接收并调用事件,但是e.Message(或q.EndReceive)应该抛出异常。 Is this not the case? 不是吗? If not, how else can I safely exit my message loop? 如果没有,我该如何安全退出消息循环?

Thanks 谢谢

UPDATE: 更新:

Here is a complete example (assumes the queue exists) 这是一个完整的示例(假设队列存在)

class Program
{
    static MessageQueue mq;
    static ManualResetEventSlim idleWH;

    static void Main(string[] args)
    {
        idleWH = new ManualResetEventSlim();

        Console.WriteLine("Opening...");
        using (mq = new MessageQueue(@".\private$\test"))
        {
            mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(int) });
            mq.ReceiveCompleted += mq_ReceiveCompleted;

            for (int i = 0; i < 10000; ++i)
                mq.Send(i);

            Console.WriteLine("Begin Receive...");
            mq.BeginReceive();

            Console.WriteLine("Press ENTER to exit loop");
            Console.ReadLine();

            Console.WriteLine("Closing...");

            mq.Close();
        }

        Console.WriteLine("Waiting...");
        idleWH.Wait();

        Console.WriteLine("Press ENTER (ex)");
        //Console.ReadLine();
    }

    static void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
    {
        try
        {
            var msg = mq.EndReceive(e.AsyncResult);
            Console.Title = msg.Body.ToString();

            // Receive next message
            mq.BeginReceive();
        }
        catch (Exception ex)
        {
            idleWH.Set();
            return;
        }
    }
}

Not quite sure how you made this work at all. 不太确定您是如何完成这项工作的。 You must call MessageQueue.EndReceive() in the event. 必须在事件中调用MessageQueue.EndReceive()。 Only that method can throw the exception. 只有该方法才能引发异常。 Review the MSDN sample code for the ReceiveCompleted event. 查看MSDN示例代码中的ReceiveCompleted事件。 And don't catch Exception, that just causes undiagnosable failure. 并且不要捕获Exception,这只会导致无法诊断的故障。 Catch the specific exception you get when you dispose the queue, ObjectDisposedException. 捕获在处理队列时遇到的特定异常ObjectDisposedException。

The only way I could get this working was with a transactional queue. 我可以使之工作的唯一方法是使用事务队列。 Any non-transactional queue appears to be vulnerable to this. 任何非事务性队列似乎都容易受到此攻击。 Not an answer, but the best advice I can give to anyone finding this. 不是答案,而是我能给发现此问题的任何人的最佳建议。

    private static volatile bool _shouldStop = false;

. . .

            _shouldStop = true;
            mq.Close();

. . .

        try
        {
            var msg = mq.EndReceive(e.AsyncResult);

            if ( _shouldStop)
            {
                idleWH.Set();
                return;
            }

            mq.BeginReceive();
        }

. . .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM