0

I am new writing singleton classes but I am running into a weird behavior. On my singleton class I have an event that is only firing once. This event is the ReceiveCompleted of the System.Messaging.MessageQueue class. My singleton class has a method GetCartAsync that requests information from another application via MSMQ to the "FleetClientQueue" queue which is the queue that the ReceiveCompleted is subscribed to. Here is the singleton class:

public sealed class CartRepository : ICartRepository
{
    private CartRepository()
    {
        if (!MessageQueue.Exists(string.Format(".\\Private$\\FleetClientQueue"))) ;
        {
            fleetClientQueue = MessageQueue.Create(".\\Private$\\FleetClientQueue");
            fleetClientQueue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Allow);
        }
        fleetClientQueue = new MessageQueue(".\\Private$\\FleetClientQueue");
        fleetClientQueue.Formatter = new XmlMessageFormatter(new[] { typeof(Cart) });
        fleetClientQueue.ReceiveCompleted += FleetClientQueue_ReceiveCompleted;
        fleetClientQueue.BeginReceive();
    }

    static ManualResetEvent expectedEchoReceived = new ManualResetEvent(false);
    Cart _cart = new Cart();        
    static MessageQueue fleetClientQueue;


   
    private static CartRepository instance = null;

    public static CartRepository Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CartRepository();
            }
            return instance;
        }
    }

    private void FleetClientQueue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
    {
        _cart = (Cart)e.Message.Body;
        expectedEchoReceived.Set();
    }

    public async Task<Cart> GetCartAsync()
    {
        MessageQueue fleetClientServiceQueue;
        fleetClientServiceQueue = new MessageQueue(".\\Private$\\FleetClientServiceQueue");
        fleetClientServiceQueue.Formatter = new BinaryMessageFormatter();
        fleetClientServiceQueue.Send("RequestCartInformation");
        expectedEchoReceived.Reset();
        expectedEchoReceived.WaitOne(5000);

      

        return _cart;
       
    }
}

Here is the code of how I am calling the method on the singleton class from a viewmodel class:

Cart = await CartRepository.Instance.GetCartAsync();

The weird part is that the first time GetCartAsync method is called the ReceiveCompleted event fires just fine. After that for some reason when I called the GetCartAsync from another view models in my application the ReceiveCompleted event is not fired. I can see the messages coming in into that queue on computer management and they just keep accumulating on the queue since it looks like they are not being processed by the singleton subscribed event.

Please if I can get some ideas of what is going on please.

user3614070
  • 131
  • 2
  • 11

2 Answers2

1

The reason that you only get this callback once is that you only call BeginReceive once. It only consumes one item from the queue.

To continue consuming call BeginReceive again in the callback:

private void FleetClientQueue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
    _cart = (Cart)e.Message.Body;
    expectedEchoReceived.Set();
    // Restart the asynchronous receive operation.
    fleetClientQueue.BeginReceive();
}

This is the approach listed in the documentation:

Jason
  • 1,505
  • 5
  • 9
0

After debugging for some time your source code I observed that in the first line of the constructor of the CartRepository you have forgotten to delete a semicolon (;) at the end of the line. As such, your MessageQueue.Create tries to run every time even if the queue exists on the system creating an exception.

It is recommended that you try to catch all the exceptions and try to handle them accordingly. Also, you don't have an else statement after the creation and as such the following command re-initializes the queue without reason:

fleetClientQueue = new MessageQueue(".\\Private$\\FleetClientQueue");

What I would do is to rewrite the constructor to something like the following:

private const string MessageQueueName = ".\\Private$\\FleetClientQueue";
private CartRepository()
{
    try
    {
        if (!MessageQueue.Exists(MessageQueueName))
        {
            fleetClientQueue = MessageQueue.Create(MessageQueueName);
            fleetClientQueue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Allow);
        }
        else
        {
            fleetClientQueue = new MessageQueue(MessageQueueName);
        }
        fleetClientQueue.Formatter = new XmlMessageFormatter(new[] { typeof(Cart) });
        fleetClientQueue.ReceiveCompleted += FleetClientQueue_ReceiveCompleted;
        fleetClientQueue.BeginReceive();
    }
    catch (Exception e)
    {
        // do something here. eg.
        // log the error in a Log file, display message to the user or whatever...
    }
}

Be careful of the fact that I have created a constant string MessageQueueName and I use that string in my calls. Your GetCartAsync() method is using a different queue name and it is likely to be wrong (".\Private$\FleetClientServiceQueue").

  • Good catch on the semicolon (;). I am still having trouble with firing ReceiveCompleted event only once. No exception on the try and catch. Any ideas why this might be happening? – user3614070 Sep 05 '20 at 19:05
  • Can you verify that everything else is working as expected and that the `FleetClientQueue_ReceiveCompleted` is not raising any exception? I don't have any minimum reproducible example. You will have to give much more details. – Efthymios Kalyviotis Sep 05 '20 at 22:06