MSMQ - Cannot receive from Multicast queues - c#

I am trying to get my head around how multicasting works in MSMQ but I cannot receive messages at all, even from the same machine. I'm obviously doing something wrong but cannot see what.
Here's where I'm at:
I manually created a non-transactional private queue called MulticastTest and then set the Multicast address to 234.1.1.1:8001. Then my test sending app does this:
MessageQueue queue = new MessageQueue("FormatName:MULTICAST=234.1.1.1:8001");
queue.Send("Hello World");
This works, it at least seems to send the message which I see in an outgoing queue on the same machine. At least I assume this is correct, please tell me if it isn't.
So now I try and run my receiving app (either on the same machine or a different one configured to the same multicast address) and I cannot get it to work. If I try this:
MessageQueue queue = new MessageQueue("FormatName:MULTICAST=234.1.1.1:8001");
var message = queue.Receive();
It simply won't work, the Receive() method throws an exception saying:
The specified format name does not support the requested operation.
For example, a direct queue format name cannot be deleted
If I try and set the receiving queue as .\private$\MulticastTest it at least waits for a message but nothing happens, all messages still stay in the outgoing queue.
So what am I doing wrong? Does some kind of service need to be running for MSMQ to send out messages from the outgoing queue?
I have also tried giving full permissions to the ANONYMOUS USER as per this question but that has no affect.

After much experimentation I finally figured out the correct steps I needed to get multicast queues to work.
First and foremost, make sure you've got the MSMQ Multicast feature installed! Despite being able to create a queue with a multicast address on one of my servers, Server Manager actually told me that the component wasn't installed.
After trying this out on my local machine instead I found this message in my event log:
Message Queuing found multiple IP addresses for the local computer.
Message Queuing will use the default IP address determined by the PGM
driver for multicast messages. To use a different IP address, set the
\HKLM\Software\Microsoft\MSMQ\Parameters\MulticastBindIP registry
value to one of the following valid IP addresses: [IP addresses listed here]
It turns out I had multiple IP address for my local area network, so first I added this registry key using the correct IP address needed to send out messages and then restart the Message Queueing service. More details can be found here: https://technet.microsoft.com/en-us/library/cc770813%28v=ws.10%29.aspx?f=255&MSPPError=-2147217396
Next I had to add permissions to my message queue for the ANONYMOUS LOGON user, so I gave (at a minimum) Receive and Send permissions.
Now to send something. The correct format of the queue name you need is as follows:
FormatName:MULTICAST=234.1.1.1:8001
or whatever your multicast IP address/port is. My sending app now sent out the message and I could see that it now appears in my private queue which is tied to this multicast address. This means that the message has definitely been sent.
On the receiving end, I need to listen to the private queue (not the multicast format above), so I listen on:
.\private$\MulticastTest
Finally I see the message I sent appear on the receiving end.
As a sanity check I setup another queue pointing to the same multicast address (making sure on that machine I followed the same steps above) and can now send a message from one machine and have it received by multiple machines.
I hope this answer is of help to others as it was a real trial-and-error effort for me.

I solved same my problem by other way:
Create private queue with multicast address.
Create queue in producer by next
const string QUEUE_PATH = #"formatname:MULTICAST=234.1.1.1:8001"
MessageQueue mq = new MessageQueue(QUEUE_PATH)
Create consumer queue next (each consumer has different name!):
consumer1:
const string QUEUE_PATH = #".\Private$\MSMQ-Task3-Consumer-1";
MessageQueue mq = !MessageQueue.Exists(QUEUE_PATH) ? MessageQueue.Create(QUEUE_PATH) : new MessageQueue(QUEUE_PATH);
mq.MulticastAddress = "234.1.1.1:8001";
consumer2:
const string QUEUE_PATH = #".\Private$\MSMQ-Task3-Consumer-2";
MessageQueue mq = !MessageQueue.Exists(QUEUE_PATH) ? MessageQueue.Create(QUEUE_PATH) : new MessageQueue(QUEUE_PATH);
mq.MulticastAddress = "234.1.1.1:8001";
Sources can be found here: https://github.com/constructor-igor/TechSugar/tree/master/MessageQueue
Short Settings explanation can be found: https://github.com/constructor-igor/TechSugar/wiki/MessageQueue

Related

How can I debug MSMQ messages not arriving on a remote server?

I have some code that sends a message to a remote queue.
var queue = new MessageQueue(queueName);
var message = new Message(queueMessage, new BinaryMessageFormatter());
queue.Send(message);
I've tried setting the queue using IP and hostname, it makes no difference:
FormatName:Direct=TCP:1.2.3.4\Private$\my.queue
FormatName:Direct=OS:servername\Private$\my.queue
The messages appear in the outgoing messages queue (if I pause it)
When unpaused they're sent to the server.
There is a private queue set up on the server. There is nothing running that will take messages off the queue.
However, messages never appear in the queue on the remote machine. I don't know how to debug this problem. The queue is a private non-transactional queue.
Creating a local private queue and sending messages to it works fine.
Are there some logs or something I can look at to see what might be happening?
The status in outgoing messages shows state as 'connected' so there is no connection issue.
Edit:
The only logging I can find is in event viewer > microsoft > windows > msmq which has an entry that simply says "Message came over network" whenever I send a message via MSMQ. It has no other information.
Solved, I added this:
message.UseDeadLetterQueue = true;
This made the server put it into the dead letter queue under System Queues > Dead-letter messages
Once this happened I could see my message and clicking it, it said 'Access Denied' under the 'Class' heading.
A quick google revealed that even though I had granted Everyone full access permissions to the queue, it was necessary to add Anonymous Logon and give that full access too in the security tab of the queue.

Remote MSMQ FormatName Error

I created a private queue on a development server that is transactional and am trying to push a message to it via C#:
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
//AppSetting has: FormatName:DIRECT=OS:.\private$\queue_name
sampleQueue = new MessageQueue(System.Configuration.ConfigurationManager.AppSettings["q"]);
var msg = new SampleMessage { CreateDate = DateTime.Now, Body = Guid.NewGuid().ToString() };
var mess = new Message(msg);
mess.UseDeadLetterQueue = true;
mess.Recoverable = true;
sampleQueue.Send(mess, MessageQueueTransactionType.Single);
scope.Complete();
}
The SampleMessage class just exposes a CreateDate and Body set of properties - completely generic, as this is just a sample.
When running the code in my local environment (Windows 10 Pro), I can put a message in the queue with the above code successfully. Similarly, if I run the same code on the development server (Windows Server 2016), the message shows up as expected.
My issue comes in with trying to put a message from my local system on to the remote queue (changing the . to the FQDN of the server, which has an entry in my HOSTS file), which kicks back The specified format name does not support the requested operation. For example, a direct queue format name cannot be deleted. if I try to access any of the properties from sampleQueue (above - example property would be MachineName), but if I don't access any properties the message just fails to deliver with no indication as to why and no errors thrown. I enabled dead-letter on the message (above), but neither transactional nor non-transactional show any failed messages, so I'm at a loss. I've also tried FormatName:DIRECT=OS, FormatName:DIRECT=TCP and checked all of the capitalization to be sure it's right with no luck. Also, I ensured Disable un-authenticated RPC calls is not checked and the Windows Firewall has been turned off on both machines.
The production environment will not be associated with an Active Directory domain, so this is all workgroup-based MSMQ. Anonymous Logon has been enabled, queue is definitely transactional and since local works, I'm stumped.
Interestingly enough, when I try to send to the remote queue I see where that pops up in Outgoing Queues. I looked at it, see that it shows a state of Connected, has 0 messages, 0 unacknowledged messages and 0 unprocessed messages. The IP it shows under Next Hop(s) is correct, so name resolution is also working.
Any suggestions? I'm trying to avoid requiring developers to create MSMQ queues on their local machines, but right now that's the only option I can see if I can't get this to work.
Update
Based on a comment below, I created a non-transactional queue called test_queue on the remote server and attempted to send a message to it. It arrived at the destination server, but went into Dead-Letter messages, with a class of The destination queue does not exist listed. The queue name in my config file shows FormatName:DIRECT=OS:remote-server-name\private$\test_queue and it's definitely a private queue, so I'm really confused since the queue is definitely there.
Got it! MSMQ will be the death of me, I swear. The remote server is not part of a domain, so to make connecting to the server easier, I created a zone inside my Active Directory instance, e.g. companyname.local and then had an entry in there for devserver.companyname.local pointing to the proper IP.
When I created the non-transactional queue and was getting the message The destination queue doesn't exist, I came across this article: https://social.msdn.microsoft.com/Forums/en-US/0d02f666-3f45-427e-9dbd-379435160471/the-destination-queue-does-not-exist?forum=msmq. It mentioned looking at the Queues tab of the message inside the Dead-letter queue and I saw the exact FormatName configuration I had setup, e.g. DIRECT=OS:devserver.companyname.local\private$\queue_name, but the properties of the queue showed a name of devserver\private$\queue_name. On a hunch, and because MSMQ is so fickle, I added a quick HOSTS entry for devserver to that IP (so I could circumvent my DNS zone) and sending to both the transactional and non-transactional queue now works!
I can't believe MSMQ cared that it got to the right server, but the server name couldn't be resolved like that. This server is in a hosted environment, so it can't hit my DNS instance, but changing it to be just the raw server name did the trickl

MSMQ via C# - ACK that message received?

I'm sending a message to a private queue via c# :
MessageQueue msgQ = new MessageQueue(#".\private$\aaa");
msgQ.Formatter = new XmlMessageFormatter(new[] { typeof (String) });
msgQ.Send(msg);
It does work and I do see the message in the queue.
However, is there any way to get an ACK whether the message got to the queue with success ?
ps
BeginPeek and PeekCompleted is an event which is raised when a message becomes available in the queue or when the specified interval of time has expired. it is not helping me because I need to know if the message that I sent was received by msmq. BeginPeek will be raised also if someone else entered a message to the queue. and the last thing I want is to check via BeginPeek - from who this message comes from.
How can I do that?
ps2
Or maybe I don't have to worry since msgQ.Send(msg); will raise an exception if a message wasn't inserted....?
I think what you are trying to do should not be handled in code. When you send the message, it is placed in the outgoing queue. There are numerous reasons why it would not reach the destination, such as a network partition or the destination queue being full. But this should not matter to your application - as far as it is concerned, it sent the message, it committed transaction, it received no error. It is a responsibility of the underlying infrastructure to do the rest, and that infrastructure should be monitored to make sure there are no technical issues.
Now what should really be important to your application is the delivery guarantees. I assume from the scenario that you are describing that you need durable transactional queues to ensure that the message is not lost. More about the options available can be read here
Also, if you need some identifier to display to the user as a confirmation, a common practice is to generate it in the sending code and place it in the message itself. Then the handling code would use the id to do the required work.
Using transactional queues and having all your machines enroll in DTC transactions likely would provide what you're looking for. However, it's kinda a pain in the butt and DTC has side effects - like all transactions are enrolled together, including DB transactions.
Perhaps a better solution would to be use a framework like MassTransit or NServiceBus and do a request-response, allowing the reviecer to respond with actual confirmation message say not only "this has been delivered" but also "I acknowledge this" with timeout options.
As Oleksii have explained about reliable delivery.
However this can effect on performance.
What I can suggest is:
Why not create a MSMQ server on the machine that is sending MSG to other system.
What I am thinking is
Server 1 sends MSMSQ to Server 2
Server 2 receives adds to queue
Server 2 process queue/fire your code here to send a MSMQ msg to Server 1
Server 1 receives MSG (any successful msg with MSGId)
Do your further task
This approach can be an extra mile, but will keep your servers out of performance Lag.

MSMQ Poison message and TimeToReachQueue

I tried creating a poison message scenario in the following manner.
1- Created a message queue on a server (transactional queue).
2- Created a receiver app that handles incoming messages on that server.
3- Created a client app located on a client machine which sends messages to that server with the specific name for the queue.
4- I used the sender client app with the following code (C# 4.0 framework):
System.Messaging.Message mm = new System.Messaging.Message("Some msg");
mm.TimeToBeReceived = new TimeSpan(0, 0, 50);
mm.TimeToReachQueue = new TimeSpan(0, 0, 30);
mm.UseDeadLetterQueue = true;
mq.Send(mm);
So this is setting the timeout to reach queue to 30 seconds.
First test worked fine. Message went through and was received by the server app.
My second test, I disconnected my ethernet cable, then did another send from the client machine.
I can see in the message queue on the client machine that the message is waiting to be sent ("Waiting for connection"). My problem is that when it goes beyond the 30 sec (or 50sec too), the message never goes in the Dead-letter queue on the client machine.
Why is it so ? ... I was expecting it to go there some it timed-out.
Tested on Windows 7 (client) / Windows server 2008 r2 (server)
Your question is a few days old already. Did you find out anything?
My interpretation of your scenario would be that the unplugged cable is the key.
In the scenario John describes, there is an existing connection and the receiver could not process the message correctly within the set time limit.
In you scenario, however, the receiving endpoint never gets the chance to process the message, so the timeout can never occur. As you said, the state of the message is Waiting for connection. A message that was never sent cannot logically have a timeout to reach its destination.
Just ask yourself, how many resources Windows/ MSMQ would unneccessaryly sacrifice - and how often - to check MessageQueues for how-many conditions if the queues is essentially inactive? There might be a lot of queues with a lot of messages on a system.
The behavior I would expect is that if you plug the network cable back in and the connection is re-established that then, only when it is needed, your poison message wil be checked for the timeout and eventually moved to the DeadLetter queue.
You might want to check this scenario out - or did you already check it out the meantime?

MSMQ Send message to Remote Queue

I am trying to send a message to a remote queue. My process isn't failing, but I still don't see the message on the remote queue? I would assume it would fail if it couldn't process the message?
I did notice that on my local machine the remote queue is listed in Outgoing queues, but don't see messages there either. Very ignorant here and all examples show that how I am doing (or so I assume) is correct.
Code (Simple for test):
using (var transaction = new TransactionScope())
{
using (var queue = new MessageQueue(#"FormatName:DIRECT=OS:mymachine\MyQueueQueue"))
{
XDocument xdoc = XDocument.Parse("<root/>");
var message = new Message(xdoc.ToString());
queue.Send(message, MessageQueueTransactionType.Single);
}
transaction.Complete();
}
Console.Read();
}
What I am doing wrong? Strange...no errors, but don't see message anywhere. Write works to my local queue.
The queue you see on your local machine is how MSMQ transmits a message from your machine to the remote machine. So don't worry about that as long as there are no messages on it. If there were messages on it that would indicate the remote queue was not available for some reason.
Likely permissions could an issue. Check the send permissions on the remote queue. If the call is going cross-domain you will need to add ANONYMOUS LOGON to your permissions.
Also try to enable to MSMQ event log (if you are running server 2008 or above).
UPDATE
It looks like you are calling a public queue address. You should be using private queues. The address is the same except for the PRIVATE$ directive:
FormatName:DIRECT=OS:mymachine\PRIVATE$\MyQueueQueue
ALSO: is your queue name myQueueQueue like in your queue address?

Categories

Resources