问题
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?
回答1:
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
回答2:
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. ;)
回答3:
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?
回答4:
Just a small typo in the code. Correction is as follows:
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;
}
回答5:
When you register a IpcServerChannel it makes a Named Pipe to communicate over with the name of the Port Name you chose for your IpcServerChannel. You can look at the list of Named Pipes to see if your Port Name is there.
System.IO.Directory.GetFiles(@"\\.\pipe\").Any((path) => path.Contains(@"\\.\pipe\" + pipeName));
来源:https://stackoverflow.com/questions/1474787/how-can-i-tell-if-another-app-has-registered-an-ipc-remoting-channel