Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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. 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;
        }
    }
}
like image 260
Barguast Avatar asked Mar 30 '11 12:03

Barguast


People also ask

Is MSMQ asynchronous?

Asynchronous messaging. With MSMQ asynchronous messaging, a client application can send a message to a server and return immediately, even if the target computer or server program is not responding.

Is MSMQ obsolete?

As a Windows component, MSMQ is technically “supported” as long as it's carried by a supported version of Windows. Since it exists in Windows 10 and Windows Server 2019, MSMQ will continue to live on until at least 2029—and much longer assuming it isn't removed from future versions of Windows.

Does .NET 5 support MSMQ?

Because NET 5 does not support MSMQ, the two main technologies that we recommend you use for migration to Google Cloud are Pub/Sub and Cloud Tasks.

What is asynchronous message queue?

A message queue is a form of asynchronous service-to-service communication used in serverless and microservices architectures. Messages are stored on the queue until they are processed and deleted. Each message is processed only once, by a single consumer.


1 Answers

Not quite sure how you made this work at all. You must call MessageQueue.EndReceive() in the event. Only that method can throw the exception. Review the MSDN sample code for the ReceiveCompleted event. And don't catch Exception, that just causes undiagnosable failure. Catch the specific exception you get when you dispose the queue, ObjectDisposedException.

like image 70
Hans Passant Avatar answered Sep 22 '22 00:09

Hans Passant