views:

511

answers:

4

So I have an application which has a .NET API available. Their API library communicates with their main application through .NET remoting calls. In order to use the API, the application must be up and running already.

So, I have an instance where I need to programmatically start the application and then instantiate one of the API objects, which attempts to open an IPC remoting channel to the main app. The problem is, after I start the process, there are a few seconds between startup and when the application registers the channel. If I try to instantiate an API object before the channel is registered, it biffs out.

It doesn't help that I know very little about .NET remoting.

How do I determine from MY application which uses their API if THEIR application has registered the channel for communication so I know it's okay to instantiate their API object?

+2  A: 

Try this:

using System.Net.NetworkInformation;
using System.Net;
 private static bool IsPortAvailable(int port)
 {
        IPGlobalProperties globalProperties = IPGlobalProperties.GetIPGlobalProperties();
        IPEndPoint[] activeListeners = globalProperties.GetActiveTcpListeners();
        if (activeListeners.Any(conn => conn.Port == port))
        {
            return true;
        }
        return false;
 }

Pass in the port and you should get a value indicating whether there is a listener on that port.Hope this helps

Abhijeet Patel
The problem is.. it's not a port. It's IPC remoting, so there are port "names" but not actual ports.
snicker
If you are programatically creating a process that listens for connections then it has to be listening on some port. This MSDN example has the server listening for IPC calls on port 9090:http://msdn.microsoft.com/en-us/library/system.runtime.remoting.channels.ipc.ipcchannel.aspxIf you don't know the port, try running netstat from the commannd line, you should be able to see what ports are in use
Abhijeet Patel
Ah, that seems to make sense. The port changes randomly, however. Any suggestions for that?
snicker
How did you deduce that the port is changing randomly?Just for kicks can you run netstat from the command line and verify that it changes randomly across different runs of the application?It might also be helpful to check if the application has a config file and whether there are any port numbers etc. specified in the config file.
Abhijeet Patel
I deduced it exactly that way: different runs of the application resulted in different port numbers, every time. The application does not specify a port number when it creates the IPC channel, which I've determined by using Reflector to look at their code.
snicker
Do you have any control over their source code, if so you could register a specific channel to ensure that the port doesn't change
Abhijeet Patel
Nope! I wish I could accept your answer, but the bounty expired and i didn't know that would prevent me from doing so. Sorry! I have bugged people on meta about it...
snicker
No worries, I'd be interested in knowing the resolution to this regardless
Abhijeet Patel
@Abhijeet: Finally...an answer. I'm glad I stumbled upon the question and saw your solution. This helped me immensely. I am going to put your solution as the answer and link it above. Thank you, thank you, thank you!!!
dboarman
A: 

Just to get out of the box for a moment, have you thought about using WCF with MSMQ? I am not sure that I fully understand you're architecture, but it sounds like the client of the API has to spin up another process that hosts the API. There may be a timing issue between when you start the API host, and when the client tries to make calls. Microsoft has recently deprecated .NET Remoting (as well as all their other previous communications technologies such as ASMX web services) as legacy, and is highly recommending that developers move to the WCF platform.

If you use WCF with MSMQ, you shouldn't have a problem with timing. Your client application can drop messages in a durable queue regardless of whether the API host is running or not. The API host can be started at any time, and it will pick up and process any messages waiting in the queue. Even if you still have the client application start up the API host, the timing problem would no longer be an issue because you are using queuing to transfer the messages rather than .NET Remoting. WCF provides a nice, convenient, easy to use wrapper around MSMQ, so the barrier to entry is relatively low.

The other beautiful thing about using WCF over .NET Remoting is that you can easily move the API host to a different physical server without having to change the client app(s). You could even move to a different queuing platform if you so desired (such as RabbitMQ on AMQP), without changing either the client or API host apps. WCF handles all of that interaction for you, providing a much cleaner decoupling and more dependable communications between your client app and API host.

If moving to WCF is not an option, you should be able to explicitly set the port with .NET Remoting. I am not sure how you are configuring your API host, but the URL for any given remoted object is usually in the form of:

tcp://<hostname>[:<port>]/<object>

If you add the port, then you should be able to use Abhijeet's solution to determine if the port is open or not. You won't gain the loose coupling and dependable communications benefits of WCF, but it would definitely be less work. ;)

jrista
WCF is not an option. I don't control the source of the server. There is a closed source application written in an unmanaged language (likely C++) and an API provided as a .NET library. The library is what creates the remoting objects. I must use remoting even though I know it is deprecated and sucks.
snicker
A: 

Have you considered wrapping the attempt to instantiate API object into a try-catch block? Then you can analyze the exception and see if it was caused by the server not listening. And if it was, you can just wait and retry.

Makes sense?

Fyodor Soikin
Yes, but unfortunately the closed source API is written poorly, and sets some static variables that prevent it from being instantiated again in the same runtime without using tons of reflection to fix it. It would be a nasty solution.
snicker
Do it in another AppDomain then?
Fyodor Soikin
I tried wrapping myObj = Activator.GetObject(...) in a try-catch block, testing for null, etc. It doesn't work because it returns a _TransparentProxy object whether the server is up or not. It's not until later when you try to use myObj that you tilt. Abjiheet has the right answer, in my opinion.
dboarman