Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MessageQueue Disposed More Than Once

I've seen this error on other posts, but not for this exact situation.

I have two classes that do the same thing with a MessageQueue. Because of that, I abstracted the creation and disposal of the queue to a helper class. I'm getting this error, and I can't see how the queue can be disposed more than once.

Object 'messageQueue' can be disposed more than once in method 'MsmqHelper.DisposeQueue(MessageQueue)'

In one of the classes, this is how the queue is used:

private MessageQueue _messageQueue;

Then, in the constructor of the class:

this._messageQueue = MsmqHelper.InitializeQueue();

Not that it really matters, but for completeness, here is where the queue is used:

this._messageQueue.Send(workflowCreated);

And here are the Dispose methods:

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
    if (disposing == false) { return; }

    MsmqHelper.DisposeQueue(this._messageQueue);
}

And this is the code in the helper class that actually calls Dispose():

public static void DisposeQueue(MessageQueue messageQueue)
{
    if (messageQueue != null)
    {
        messageQueue.Close();
        messageQueue.Dispose();
        messageQueue = null;
    }
}

Where is it possible for the queue to be disposed more than once in this situation?

** Edit **

I thought it would be nice to add my comments, in the conversation below, here. It's a good summary, along with the accepted answer:

I think I get it now. The messageQueue method parameter has nothing to do with the original (this._messageQueue) reference to the object. So checking messageQueue for null, and setting it to null, does no good. The caller could still pass in its variable (this._messageQueue) even after being disposed. Hence, being able to be disposed more than once.

By the way, even setting the caller's variable (this._messageQueue) to null, in the calling method, doesn't help. The problem exists solely in MsmqHelper.DisposeQueue(). So the answer is to pass by ref or simply don't call DisposeQueue() and do it all in the calling method.

** Edit 2 **

After trying this, I get the same error. I simply don't get it.

public static void DisposeQueue(ref MessageQueue messageQueue)
{
    if (messageQueue == null) { return; }

    messageQueue.Close();
    messageQueue.Dispose();
    messageQueue = null;
}

** Edit 3 -- Bug? **

I'm starting to think that this may be a bug. If I comment messageQueue.Dispose(), the error goes away. HOWEVER, I can call messageQueue.Close() and messageQueue.Dispose() together in the calling method. Go figure. I think I'm just going to make these same calls from the calling methods, or only call Close() or Dispose() instead of both.

like image 615
Bob Horn Avatar asked Mar 20 '12 21:03

Bob Horn


1 Answers

Close frees all resources of the MessageQueue object. See the documentation here. The error is most likely generated in CA because it sees that the execution path of Close also calls Dispose.

From the documentation:

    public  void ReceiveMessage()
    {
        // Connect to the a on the local computer.
        MessageQueue myQueue = new MessageQueue(".\\myQueue");

        // Set the formatter to indicate body contains an Order.
        myQueue.Formatter = new XmlMessageFormatter(new Type[]
            {typeof(String)});

        try
        {
            // Receive and format the message. 
            Message myMessage1 = myQueue.Receive();
            Message myMessage2 = myQueue.Receive();
        }

        catch (MessageQueueException)
        {
            // Handle sources of any MessageQueueException.
        }

        // Catch other exceptions as necessary.

        finally
        {
            // Free resources.
            myQueue.Close();
        }

        return;
    }

Close apparently will release the resources but will allow the component to reacquire them if they haven't been collected yet. It might be more prudent to open the MessageQueue object, use it, and then close it within the same call rather than open it for a period of time and closing it later because connection caching removes the overhead of opening the MessageQueue in repeated calls.

*UPDATE* It appears that CA treats CA2202 differently for member fields versus passing the disposable object to a method, even if that method is private to the class. Regardless, according to the documentation, you should only have to call Close() or Dispose() but not both. I recommend however changing your design so that you create, use, and then close the MessageQueue object all within the scope of your message operations like the example from the documentation example demonstrates above.

like image 104
Jim Avatar answered Oct 21 '22 05:10

Jim