WCF ServiceHost.Close () Delay

I have a simple WCF service for WCF duplex, which I am trying to stop programmatically. If I do not have connected users, ServiceHost.Close () is very fast, but if I even have one connected user, I find the Close () function, which takes a lot of time, sometimes> 30 seconds. Is this normal behavior?

Abort (), on the other hand, is almost instantaneous, and I am tempted to use this.

+6
c # wcf duplex
source share
5 answers

It can be. The docs indicate that

The Close method allows any work in progress to be completed before returning. For example, complete sending any buffered messages.

There is an overload on Close() that accepts a TimeSpan (and throws if the time interval is exceeded)

Abort() looks like the best way to stop the WCF host without delay.

+10
source share

Make sure you close the client connection, for example:

 var channel = factory.CreateChannel(); var channel.DoSomethingForMe(); (channel as ICommunicationObject).Close(); 

If you do not do this Close () on the channel, Close () on the server will wait a very, very long time, even if you specify a short timeout.

+6
source share

If you're okay with killing any incoming service calls, then Abort () is the way to go. Close () is a polite way to close a service.

+1
source share

I could see the advantage of Abort () over Close () for expediency, but I would suggest that something bad could happen. In my case, I want to wait for Close () so that I can reuse port (s). This code will wait until services are actually closed before resuming.

 Semaphore cont=new Semaphore(0, 1); foreach (ServiceHost s in WCFServices) { try { s.Closed += delegate(Object o, System.EventArgs n) { cont.Release(); }; s.Close(); cont.WaitOne(); } catch (Exception) { }//try }//for 
0
source share

I also noticed this problem. My code initially looked like this:

 [TestMethod] [Timeout(2000)] public void ApiClientTest() { bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false; Api apiService = new ApiTestService(); var clientService = new ClientTestService(); ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService)); ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService)); //To let us know the services were successfully opened clientHost.Opened += (s, e) => ClientSuccessSet = true; apiHost.Opened += (s, e) => ApiSuccessSet = true; clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName); apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName); clientHost.BeginOpen(OnOpen, clientHost); apiHost.BeginOpen(OnOpen, apiHost); //This allows both services to be open for communication. while (!ApiSuccessSet || !ClientSuccessSet) Thread.Yield(); EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName); EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName); InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback()); var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint); var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint); var ClientChannel = ClientChannelFactory.CreateChannel(); var ApiChannel = ApiChannelFactory.CreateChannel(); clientHost.Close(); apiHost.Close(); } void OnOpen(IAsyncResult ar) { ServiceHost service = (ServiceHost)ar.AsyncState; service.EndOpen(ar); } 

I noticed that this code took 20 seconds. Then I decided to close the canal plants as follows:

  [TestMethod] [Timeout(2000)] public void ApiClientTest() { bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false; Api apiService = new ApiTestService(); var clientService = new ClientTestService(); ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService)); ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService)); //To let us know the services were successfully opened clientHost.Opened += (s, e) => ClientSuccessSet = true; apiHost.Opened += (s, e) => ApiSuccessSet = true; clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName); apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName); clientHost.BeginOpen(OnOpen, clientHost); apiHost.BeginOpen(OnOpen, apiHost); //This allows both services to be open for communication. while (!ApiSuccessSet || !ClientSuccessSet) Thread.Yield(); EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName); EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName); InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback()); var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint); var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint); var ClientChannel = ClientChannelFactory.CreateChannel(); var ApiChannel = ApiChannelFactory.CreateChannel(); ClientChannelFactory.Close(); ApiChannelFactory.Close(); clientHost.Close(); apiHost.Close(); } 

This makes me think that it takes a long time to get rid of the context of the client instance.

I suspect there are 3 ways to better deal with this decision.

First, create a function on the client that controls session termination. Thus, you can call this method before the service plans are closed, and this will speed up the shutdown time.

the second is to close asynchronously and perform other processing until the connection closes.

The third is to program the client when you need to close the connection (especially if you manage both the client and the service) so that the client can end the session itself and the service can shut down gracefully and quickly.

0
source share

All Articles