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.
Related
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
So I'm trying to get MSMQ messages forwarded from one machine to another (which is dead easy - I was surprised), but one of the requirements from the ops side of the house is that we need to be able to see a log entry somewhere when the remote server decides not to accept a message. For example, if I try to send to a nonexistent queue, like so:
MessageQueue remoteQueue = new MessageQueue(#"FormatName:Direct=OS:machinename\private$\notarealqueue");
remoteQueue.Send("Test", MessageQueueTransactionType.Single);
The message goes into the local delivery queue, and appears to get sent across the network, but because the queue doesn't exist, the remote MSMQ manager discards the message. However, there's no entry in the Event Log that I can find about the message being dropped on the floor, and that makes people nervous. The Microsoft/Windows/MSMQ/EndToEnd log only seems to involve successful messages, which doesn't seem particularly useful. Is there a log I'm not seeing somewhere?
You can use MSMQ dead letter queues for that.
message.UseDeadLetterQueue = true;
With that enabled, if message can't be delivered it will be sent to one of two system dead letter queues - one for transactional and one for non transactional messages. You'll also find there the reason why message was not delivered, which was the original destination queue, full message body, label, etc.
You can use one of tools for managing queues to resend or recover these messages.
The event log is solely for the health state of MSMQ. What happens to a single message is trivial and not logged in the event log. Imagine what would happen if a million messages were discarded and had to be logged in the event log.
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
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?
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?