How can I test programmatically to see if a particular net pipe service is running and listening, so I don't get a "There was no endpoint listening at..." exception?
So for instance if I have this code:
Uri baseAddress = new Uri("http://localhost/something");
var _ServiceHost = new ServiceHost(typeof(Automation), new Uri[] { baseAddress });
NetNamedPipeBinding nnpb = new NetNamedPipeBinding();
_ServiceHost.AddServiceEndpoint(typeof(IAutomation), nnpb, "ImListening");
_ServiceHost.Open();
I want from another application communicate with http://localhost/something/ImListening
but before I want to make sure is listening so I don't get an exception, or is the exception the only way to test this?
Listen for the exception. That is the proper way to do it.
Exceptions exists for a reason, I would just handle the exception, as long a you handle it the user wont get a cryptic error message, which I guess is what you are trying to avoid.
Perhaps is not the best way, but I not found another way to test an endpoint using NetNamedPipe
.
I usually do this approach:
public void IsValid()
{
RegisterConfiguration();
var endPoints = Host.Description.Endpoints;
if (!endPoints.HasElements())
{
throw new NullReferenceException("endpoints (WCF Service).");
}
foreach (var item in endPoints)
{
var service = new ChannelFactory<ITcoService>(item.Binding, item.Address);
try
{
var client = (IClientChannel)service.CreateChannel();
try
{
client.Open(TimeSpan.FromSeconds(2));
throw new InvalidOperationException(
string.Format(
"A registration already exists for URI: \"{0}\" (WCF Service is already open in some IChannelListener).",
item.Address));
}
catch (Exception ex)
{
if (ex is System.ServiceModel.CommunicationObjectFaultedException ||
ex is System.ServiceModel.EndpointNotFoundException)
{
Debug.WriteLine(ex.DumpObject());
}
else
{
throw;
}
}
finally
{
new Action(client.Dispose).InvokeSafe();
}
}
finally
{
new Action(service.Close).InvokeSafe();
}
}
}
(sorry the extension methods in this code, InvokeSafe
is just a try/catch to execute a Action
and HasElements
just test if a collection is different of null and empty).
If you use ChannelFactory.CreateChannel
, it returns a proxy that implements your service's interface without opening a communication channel. However, the proxy also implements IClientChannel
, which you can use this to check if the endpoint is up. In my case I also needed to wait for the endpoint to start, so I used a loop with a timeout:
public static Interface CreateOpenChannel<Interface>(Binding protocol, EndpointAddress address, int timeoutMs = 5000)
{
for (int startTime = Environment.TickCount;;) {
// a proxy is unusable after comm failure ("faulted" state), so create it within the loop
Interface proxy = ChannelFactory<Interface>.CreateChannel(protocol, address);
try {
((IClientChannel) proxy).Open();
return proxy;
} catch (CommunicationException ex) {
if (unchecked(Environment.TickCount - startTime) >= timeoutMs)
throw;
Thread.Sleep(Math.Min(1000, timeoutMs / 4));
}
}
}
This was tested with NetNamedPipeBinding
. I am unsure whether this will behave the same way with other bindings, or whether Open()
merely opens a connection or also tests the validity of the connection (e.g. whether the host interface matches the client interface).