I'm trying to setup msmq communication between two services on two separate machines within the same domain.
The machines are a Primary - Secondary situation.
I need to be able to Send and Purge from the Primary, and Receive from the Secondary
I can't seem to find a setup that allows for this. I had one setup where the queues existed on the Secondary and the Primary could Send and the Secondary Receive BUT I could not purge from the Primary as I need to. I believe this was due to the queues being private and remote.
So I tried to flip the situation. I put the queues on the Primary, but then I couldn't Send to the private local queue, so I made them public, and now I cant get the secondary to find the remote public queues.
if (!MessageQueue.Exists(queueName))
{
//log they don't exist and exit
throw new Exception("One or more of the required queues do not exist");
}
syncQ = new MessageQueue(queueName){Formatter = new XmlMessageFormatter(new Type[] {typeof (String)})};
if (machineState == MachineState.Primary)
{
syncQ.SetPermissions(ASPConfiguration.SyncUser, MessageQueueAccessRights.FullControl, AccessControlEntryType.Allow);
syncQ.Purge();
}
Primary = ".\nw"
Secondary = "FormatName:Direct=OS:CACTEST-WS-D\nw"
It doesn't really matter if the queues are private or public to me just as long as I can do what I need.
Thanks for the Help.
In answer to your queries:
I had one setup where the queues existed on the Secondary and the
Primary could Send and the Secondary Receive BUT I could not purge
from the Primary as I need to.
The initial set up you had, with the queue on secondary and primary sending to secondary is the correct configuration. Unsure why you are unable to purge secondary queues from primary. This is probably just a simple case of queue permissions. Try granting full control to the service account running on primary.
So I tried to flip the situation. I put the queues on the Primary, but
then I couldn't Send to the private local queue
Again, unsure why this is. What errors do you receive? You can enable MSMQ tracing which will give you any transmission errors on both machines. Anyhow, this is not the correct configuration. It's always best to send remote - receive local.
Primary = ".\nw"
It's always better to use the fully formatted msmq address in all situations to avoid addressing problems.
It doesn't really matter if the queues are private or public to me
Well it really really does matter. Public queues are for enterprise-scale configurations with high volume, clustering and/or routing requirements, and anyhow you have to register them with active directory for them to even work. If you just want to send stuff from place to place ALWAYS use private queues.
My advice is to revert back to you initial setup and concentrate on getting the remote purge working.
Related
I'm writing a pretty big web system with asp.net MVC, which involves sending data in Real Time to numerous users, based on what they are subscribed to.
My team and I decided to use SignalR for that, and I am in charge of implementing it in the system.
In our case, that a user picks a group to join, and then picks 1 Thing to work on.
For that, I'm saving all the users in a DB. I'll be using the SignalR Groups to handle the first category, and when I need to push a message to a specific user (for the other thing hes picking) I'll just get his ConnectionID from the DB.
Here's the problem - every time the page is refreshed (for instance, when the user picks a group to join) he gets a new connectionID. And now he won't see anything that's pushed to him.
I saw that in the SignalR beta, and on version 2 (I only have 1.1.1 on the computer I'm working on) you can make your own IUserIdProvider (IUserIdPrefixGenerator in the beta), or IUserConnectionIdFactory etc. So I can give him the I'd I want him to have, but I don't seem to have any of those in my version of SignalR.
There are many ways to solve this, but perhaps one of the simplest ways is to associate the new connection id with the user (maybe they still have the other connection open in a different tab). This can be done using any combination of IP Address, User-Agent, Headers, or location. Another good candidate for this is either to use sessions, or just a simple identifier cookie (which is more or less what a session would do anyway).
I'll often use GUIDs for this and then create a table in the database when a new identifier cookie is created. Every time the user "refreshes" or opens a new tab, the cookie can be read in JS and sent with the hub.connect(). Then, you can create an association between the new connection id and the existing identifier cookie.
I'd highly recommend figuring out a different way to maintain your users' persisted connections. Typically, I keep all of my users connection ids stored in a concurrent dictionary to allow for thread-safe access to the collection. I remove the users from the dictionary whenever a disconnection event occurs and I add them whenever a connection event occurs.
SignalR will manage your users' connections for you. For you to do it in the database and fall out of sync with SignalR circumvents a lot of the mechanics that make it work correctly in the first place.
private readonly static Lazy<App> _instance = new Lazy<App>(
() => new App(GlobalHost.ConnectionManager.GetHubContext<AppHub>().Clients));
private readonly ConcurrentDictionary<string, User> _users = new ConcurrentDictionary<string, User>(StringComparer.OrdinalIgnoreCase);
private IHubConnectionContext Clients { get; set; }
public App(IHubConnectionContext clients)
{
Clients = clients;
}
I am trying to use
Process[] processes = Process.GetProcessesByName(processName, workerRoleIPAddress);
From my controller to check if a certain process is running in my worker role. What is the correct IPAddress to use for the worker role? Using the IPAddress that the Input Endpoitns use doesn't seem to work.
Is there a better way to do this?
You are not forced to use the second parameter. There are two method signatures:
http://msdn.microsoft.com/en-us/library/System.Diagnostics.Process.GetProcessesByName(v=vs.71).aspx
public static Process[] GetProcessesByName(string);
public static Process[] GetProcessesByName(string, string);
I suggest you try to get clear with the first method signature. After, try to use the IP address.
I would try 127.0.0.1 first. This is the shortest way to try. Maybe even 'localhost' would be working.
Then, I don't know this precise in detail, but to ask a process list on a distant computer, this method will need some service running on the distant computer. So there might be firewall ports need to be opened opened or a certain demon need to be running on the other computer. Asking a list of processes on a distant computer will quickly become a security issue.
I eventually solved the problem by using an Azure Storage table.
I queried the worker role locally using GetProcesssByName() and stored the result in an Azure Storage table. I subsequently accessed this table from the web role to read the result.
Care must be taken to delete the older entries from the storage table so we don't assume that older(and currently non-existent) processes are still running.
My machine is in Domain D1 and there are public MSMQs in a remote server in domain D2. I am connected through vpn to D2, i.e I can RDP the machine in D2 and access the MSMQ.
What I want is to access (Know the message count) of the MSMQ without RDPing the system. So I build an application for this. I used Impersonation to impersonate the user of D2(i.e used credentials of D2)but the problem is I am not able to access the "Public" MSMQ ( used Messagequeue.GetPublicQueue() ) and exceptions are thrown with message "A workgroup installation computer does not support the operation." but when I used MessageQueue.GetPrivateQueue() it returned a collection of private queue.
I tried using MSMQManager for messageCount
Path = #"Direct:OS:machine\publicqueue";
FormatName=null;
new MSMQManager.inIt(machineName, path , FormatName);
This also throws an exception either the queue is not present or not open. but I can check that queue is working fine.
Are you comfortable doing a tiny bit of programming? If not, are you comfortable using PowerShell?
Either way - I would check out this post as it seems to contain the answers you are looking for.
Good luck, hope this helps
Your problem might be that you are working remotely.
The method GetPublicQueuesByMachine() is indeed not available over remote access.
You can see this in a feature matrix in the MSDN documentation: MessageQueue.GetPublicQueuesByMachine:
The following table shows whether this method is available in various Workgroup modes.
Workgroup mode Available
-------------- ---------
Local computer No
Local computer and direct format name No
Remote computer No
Remote computer and direct format name No
Also check the access privileges of your queues.
If I am wrong in the previous suggestion, it might be as simple as experimenting with the access rights for specific users in the network.
MSDN article Public and private queues states:
Default security access for public queues gives everyone permission to
send messages to a public queue. Specific permissions must be
granted for read access.
As for the actual message counting, John Opincar wrote a nice article about counting messages here: Counting Messages in an MSMQ MessageQueue from C#
How can I notify another application which is in different domain that current running application has crashed?
in the other words, Is it possible to negotiate two different applications in separate domain?
Thanks in advance.
You can use named pipes for this sort of IPC. For this, look into System.IO.Pipes namespace and excellent NamedsPipeServerStream & NamedPipeClientStream classes.
Note that you can use anonymous pipes only for inter process communications within the same domain, while you can use named pipes for IPC in separate domains (i.e. across PCs on the same intranet).
Yes it is possible. How well this is supported in .NET types will vary depending on how you are going to make the determination of "has crashed".
Basically the monitoring application needs to supply credentials suitable to access the system that should be running the monitored application. This is exactly what one would do to copy a file to/from another domain by starting with something like:
net use \\Fileserver1.domain2.com\IPC$ /user:DOMAIN\USER PASSWORD
or its API equaivalent.
If you use WMI (this is the obvious approach, it is easy to list the processes on a remote system with a query for Win32_Process) you can supply credentials (eg. with the scripting interface or in .NET).
You can use the AppDomain.UnhandledException event to signal the other AppDomain, possibly through a named Mutex. Since they're system-wide, you could create one called "MyAppHasCrashed" and lock it immediately. When you hit an unhandled exception, you release the mutex. On the other side, have a thread that waits on the mutex. Since it's initially blocked, the thread will sit waiting. When an exception occurs, the thread resumes and you can handle the crash.
Mutex crashed = new Mutex(true, "AppDomain1_Crashed");
...
private void AppDomain_UnhandledException(...)
{
// do whatever you want to log / alert the user
// then unlock the mutex
crashed.ReleaseMutex();
}
Then, on the other side:
void CrashWaitThread()
{
try {
crashed = Mutex.OpenExisting("AppDomain1_Crashed");
}
catch (WaitHandleCannotBeOpenedException)
{
// couldn't open the mutex
}
crashed.WaitOne();
// code to handle the crash here.
}
It's a bit of a hack, but it works nicely for both inter-domain and inter-process cases.
My program is successfully using .NET's MessageQueue class to read from an MSMQ. The queue is user configurable, and is sometimes on the local machine, and sometimes on a remote machine. The user can specify the remote machine either by name or IP address, and the queue name (and I'm only using "Private" queues).
I want to display to the user how many messages remain in the Queue, but haven't found a way to do this. The MessageQueue class does not seem to have a Count (or similar) property to give this to me easily.
I've been able to use the PerformanceCounter and PerformanceCounterCategory classes to get the count - but this only seems to work for me on the local machine (although I'm not completely sure I'm using these classes correctly).
My question is how to read the Count (number of messages) from an MSMQ on a remote machine?
I use the following method for message counting (works for both local and remote queues),
var machineName = "mymachine01";
var formatName = "FormatName:DIRECT=OS:mymachine01\private$\ftpreceived":
try
{
var msmqManagement = new MSMQ.MSMQManagement();
msmqManagement.Init(machineName, null, formatName );
return (uint)msmqManagement.MessageCount;
}
catch (COMException ex)
{
// If queue is not active or does not exist.
if (ex.ErrorCode == -1072824316)
{
return 0;
}
throw;
}
Note: It returns 0 in the case the queue does not exist or is not active as the MSMQ Managment API considers this the same error.
Note: If the machine name value is null it will look at the queue on the local machine.
Note: If the machinename variable is different from the machinename part of the formatname, it will return a count of messages in the "Outgoing" message queue with the given format name on the machine specified by machinename.
Active means it has 1 or more messages in it, or it has had a message in it within the last N (Not sure how big N is :)) seconds, after that time the queue is considered inactive.
The most reliable solution for getting the count of messages in a local queue is to use the MSMQ APIs using P/Invoke. There's a nice article here: Counting the number of messages in a Message Queue in .NET.
I don't know if it works with remote queues, but I wouldn't rely on it. Generally, the only thing you should do with a remote queue is to send a message. Trying to read messages or properties from a remote queue should be avoided, if possible. "Send remote and read local" will always give you the best performance and avoid all kinds of problems (e.g., what if the remote machine isn't available?)
I am using WMI to get this information. The following is an example of the code that I am using to accomplish this.
var query = String.Format("select MessagesinQueue from Win32_PerfRawdata_MSMQ_MSMQQueue where name ='{0}'", path.Replace("\\", "\\\\"));
var selectQuery = new SelectQuery(query);
using (var searcher = new ManagementObjectSearcher(selectQuery))
using (var results = searcher.Get())
{
foreach (var result in results)
{
var messages = result["MessagesinQueue"].ToString();
return long.Parse(messages);
}
}
This may be a solution for you: http://jopinblog.wordpress.com/2008/03/12/counting-messages-in-an-msmq-messagequeue-from-c/
This might be overkill, but you could possibly put a WCF service on the same machine hosting your queue, so you'd be able to retrieve the count using the performance counters in the WCF service and expose that functionality through a method of that service.
I would like to say several things here.
Before I get to my own answer, I would like to comment John Opncar's solution (in Dr. Wily's Apprentice answer). His code does work on remote machines. I used his code in our project at work to watch the queues on a remote cluster server and it works very well.
So, if get "RemoteMachineNotAvailable" errors, please check your configurations. Are all machines in the same network or - not to forget - are the queue's security permissions on the remote machine set up to allow others to read them?
Do the users/ accounts have sufficient rights to read from other systems?
For example, we had to allow everyone on the clustered queues.
As far as I know the PerformanceCounters do indeed have problems to read message properties on remote machines. I tried to use them for queues in a Windows Server cluster environment, but was never able to get it working. I did some internet research at that time, but unfortunatelly I do not recall if this is due to security reasons or simply a bug. :-(
Now to the actual answer. If you do not like the Cursor-Method as described by John Opincar you could also use the MessageQueue.GetAllMessages() or MessageQueue.GetMessageEnumerator methods.
I never tried GetMessageEnumerator, but I can say that I would not recommend GetAllMessages().
We suffered from heavy performance issues when using it every second on a system with several queues that contain several thousands of messages.
The method takes a snapshot of all messages in the queue, which can cause heavy loads in memory and network.
The cursor-methodis still somewhat slow. But, at least in our production environment, it feels more snappy than with the GetAllMessages() solution.
If counting the messages in your scenario does not need to be as often as one second and you have less messages to count than we do, then working with GetAllMessages() or GetMessageEnumerator() might be a possible solution for you.
Finally, it always comes down to your own individual needs.