Reputation: 7212
In a client, I'm trying to connect to a WCF changing OpenTimeout
property to 5 seconds but it's not working.... here is how I'm creating the channel:
NetTcpBinding bind = new NetTcpBinding(SecurityMode.None);
bind.OpenTimeout = new TimeSpan(0, 0, 5);
var channel = new ChannelFactory<IService>(bind, new EndpointAddress(myAddr));
channel.CreateChannel();
After this, I'm calling the method but if the server is out, it takes 21 seconds and not the 5 that I changed on OpenTimeout
, Am I missing something?
Tks
Upvotes: 6
Views: 7485
Reputation: 3248
The first call to a method on the service also opens the channel. This is called auto-open, and it is not recommended. Instead, you should call it explicitly:
channel.Open();
channel.RetrieveFoobars();
However, the problem remains: channel.Open() does not respect the binding's OpenTimeout, instead waiting approximately 21 seconds before throwing an EndpointNotFoundException. I would guess this is a bug in WCF's CommunicationObject.
It does not help, with the above code, to set ((IContextChannel)channel).OperationTimeout
, bind.SendTimeout
, or bind.OpenTimeout
. (as suggested elsewhere).
The solution I settled on, based on this VB code, is to use the asynchronous methods, which allow you to specify how long to wait before cancelling.
private void CloseChannel(ICommunicationObject channel){
try {
channel.Close();
} catch {
channel.Abort();
}
}
private void OpenChannel(ICommunicationObject channel, TimeSpan timeout) {
var ar = channel.BeginOpen(null, null);
if (!ar.AsyncWaitHandle.WaitOne(timeout, true)) {
CloseChannel(channel);
throw new EndpointNotFoundException();
}
channel.EndOpen(ar);
}
You still have to first set the binding's OpenTimeout to at least 50ms, otherwise BeginOpen throws a TimeoutException.
bind.OpenTimeout = TimeSpan.FromMilliseconds(100d)
Upvotes: 1
Reputation: 51
I resolved this problem in the next way. It seem to be works.
protected TServiceContract CreateChannel()
{
TServiceContract channel = factory.CreateChannel();
var ar = ((IChannel)channel).BeginOpen( null, null );
if( !ar.AsyncWaitHandle.WaitOne( factory.Endpoint.Binding.OpenTimeout, true ) )
{
throw new TimeoutException( "Service is not available" );
}
((IChannel)channel).EndOpen( ar );
return channel;
}
Upvotes: 5
Reputation: 3481
It appears that there are other things WCF does which are not counted in opentimeout. Look at this thread
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/5f347965-13bf-4a2d-ae82-74ad38a8d7d1/
[Edit] When I tried this with .Net 4.0, when wcf service is not available the timeout is occurring with in 2secs. Opentimeout has no affect. If wcf service is available but not responding for what ever the reason, you can make the client to wait as long as you want by setting sendtimeout setting on binding.
Upvotes: 0
Reputation: 7212
The solution that I found is checking if the wcf server is up(before calling the method), here is how:
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.ReceiveTimeout = sock.SendTimeout = 500;
IAsyncResult res = sock.BeginConnect(ip, port, null, null);
bool success = res.AsyncWaitHandle.WaitOne(500, true);
Upvotes: 1