I get the exception when executing the following code. Any ideas what is wrong?
string queueName = \"FormatName:Direct=TCP:1.1.1.1\\\\Private$\\\\test\";
Message
You cannot use the Exists method on a remote queue, so you have to impersonate a user on that remote machine:
//usings
using System;
using System.Messaging;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
//Declaring the advapi32.dll
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken);
private void IterateRemoteMQ()
{
IntPtr userToken = IntPtr.Zero;
bool success = LogonUser(
"REMOTE_USERNAME", //Username on the remote machine
".", //Domain, if not using AD, Leave it at "."
"PASSWORD", //Password for the username on the remote machine
9, //Means we're using new credentials, otherwise it will try to impersonate a local user
0,
out userToken);
if (!success)
{
throw new SecurityException("Logon user failed");
}
//Go through each queue to see if yours exists, or do some operation on that queue.
using (WindowsIdentity.Impersonate(userToken))
{
MessageQueue[] Queues = MessageQueue.GetPrivateQueuesByMachine("192.168.1.10");
foreach (MessageQueue mq in Queues)
{
string MSMQ_Name = mq.QueueName;
}
}
The answer above with checking the exception message does work on systems that raise English-exceptions. My system raises Dutch-exceptions. I get "De time-out voor de gevraagde bewerking is verstreken." So it's not a very robust solutions The exception has a property MessageQueueErrorCode that should be used to check whether or not an IOTimeout occurred.
So it's better to use
return (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout);
instead of:
return ex.Message.StartsWith("Timeout");
From your sample, it looks like you're trying to check whether a remote private queue exists, but as the MessageQueue.Exists documentation says:
Exists cannot be called to verify the existence of a remote private queue.
Trying to do so will produce an InvalidOperationException
.
If you really need this information for your workflow, you can use the MessageQueue. GetPrivateQueuesByMachine method and iterate the results to find a match. If you do, I recommend reading Are Remote MSMQ Queues Reliable?, which discusses this approach in some depth.
This post from the excellent "MSMQ from the plumber's mate" blog suggests another alternative: don't even check whether your queues exist, "but instead handle the non-delivery of the message should it turn out that the queue doesn't exist." (You'll need to track administration queues and/or dead-letter queues, but you should probably be doing that anyway.)
I ended up with the answers from Svix, Erwin van Dijk and Joseph Daigle combined. Additionally I checked for ArgumentException
:
/// <summary>
/// Checks if a (remote) Microsoft Message Queue is available
/// </summary>
/// <param name="queueName">The name of the Message Queue.</param>
/// <returns>Returns true if the queue is available otherwise false.</returns>
public static bool IsQueueAvailable(string queueName)
{
MessageQueue queue;
try
{
queue = new MessageQueue(queueName);
queue.Peek(new TimeSpan(0, 0, 5)); // wait max. 5 sec. to recieve first message from queue (reduce if necessary)
return true;
}
catch (Exception ex)
{
if(ex is ArgumentException)
{ // the provided queue name is wrong.
return false;
}
else if (ex is MessageQueueException)
{ // if message queue exception occurs either the queue is avialable but without entries (check for peek timeout) or the queue does not exist or you don't have access.
return (((MessageQueueException)ex).MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout);
}
// any other error occurred.
return false;
}
}
Try this...
public static bool IsQueueAvailable(string queueName)
{
var queue = new MessageQueue(queueName);
try
{
queue.Peek(new TimeSpan(0, 0, 5));
return true;
}
catch (MessageQueueException ex)
{
return ex.Message.StartsWith("Timeout");
}
}
If the queue doesn't exist or if the account running the app doesn't have sufficient rights to get to it, the exception message clearly states so.
AND, this would work with both FormatName and the usual queue path.