2009-06-22 7 views
6

Ho un semplice servizio TCP duplex WCF che sto cercando di arrestare a livello di programmazione. Se non ho utenti connessi, ServiceHost.Close() è molto veloce, ma se ho anche un utente connesso, trovo che la funzione Close() richiede un bel po 'di tempo, a volte> 30 secondi. È questo il solito comportamento?WCF ServiceHost.Close() Ritardo

D'altra parte, Abort() è quasi istantaneo e sono invece tentato di utilizzarlo.

risposta

10

Potrebbe essere. Lo stato docs che

Il metodo Close consente a qualsiasi incompiuta lavoro da completare prima di tornare. Ad esempio, terminare l'invio di eventuali messaggi bufferizzati .

C'è un sovraccarico di Close() che prende un TimeSpan (e throws se il periodo di superamento)

Abort() sembra il modo migliore per fermare un host WCF senza indugio.

1

Se si sta effettuando l'eliminazione di chiamate di servizio in corso, Abort() è la strada da percorrere. Close() è il modo educato per chiudere un servizio.

0

Potrei vedere il vantaggio di Abort() su Close() per convenienza, ma immagino che possa accadere qualcosa di brutto. Nel mio caso, voglio aspettare Close() in modo da poter riutilizzare la/e porta/e. Questo codice attenderà che i servizi vengano effettivamente chiusi prima di riprendere.

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

Sono sicuro che è possibile riorganizzare questo in modo che tutti i "s.Close()" vengano inviati per primi, quindi attendere il semaforo. –

6

Assicurarsi che si sta chiudendo la connessione client-side, come questo:

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

Se non si esegue questa operazione Close() sul canale, Close() su di attesa del server un tempo molto, molto lungo, anche se si specifica un breve timeout.

+0

questo ha funzionato per me – Pompair

0

Ho notato anche questo problema. mio codice è in origine si presentava così:

[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); 
    } 

ho notato che il questo codice ha preso 20 run secondsto. Ho quindi deciso di chiudere le fabbriche di canale come questo:

[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(); 
    } 

Questo mi porta a credere che il lungo tempo necessario è lo smaltimento contesto istanza del cliente.

Sospetto che ci siano 3 modi per gestire meglio questa soluzione.

Il primo è creare una funzione sul client che gestisce la fine della sessione. In questo modo è possibile chiamare tale metodo prima che i piani di servizio si chiudano e accelererà il tempo di spegnimento.

il secondo è chiudere in modo asincrono ed eseguire altre elaborazioni mentre la connessione si sta chiudendo.

Il terzo è programmare nel client quando chiudere la connessione (soprattutto se si controllano sia il client che il servizio) in modo che il client possa terminare la sessione stessa e il servizio possa arrestarsi in modo semplice e rapido.