2009-06-22 25 views
6

プログラムで停止しようとしている単純なWCF二重TCPサービスがあります。接続されたユーザーがいない場合、ServiceHost.Close()は非常に速いですが、接続されたユーザーが1人でも、Close()関数がかなりの時間を要し、30秒を超えることがあります。これはいつもの行動ですか?WCF ServiceHost.Close()遅延

一方、Abort()はほとんど瞬間的で、代わりに使用するように誘惑されています。

答えて

10

ある場合があります。 Closeメソッドは、任意の未完 作業が返す前に完了することを可能にする

ことdocs状態。 たとえば、 バッファされたメッセージの送信を完了します。

(タイムスパンを超えた場合とthrowsTimeSpanを取るClose()への過負荷

Abort()は、遅滞なくWCFホストを停止するための最良の方法のように見えるがあります。

1

進行中のサービスコールを強制終了する場合は、Abort()を使用してください。 Close()は、サービスを終了する丁寧な方法です。

0

私は、便宜のために、Close()に比べてAbort()の利点を見ることができましたが、何か悪いことが起こるかもしれません。私の場合は、Close()を待ってポートを再利用できるようにしたい。このコードは、サービスが再開する前に実際に閉じられるのを待ちます。

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

これを再配置して、すべての "s.Close()"が最初に発行され、セマフォを待つことができると確信しています。 –

6

あなたはこのように、クライアント側の接続をクローズしていることを確認します:

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

サーバーが待機する上で、クローズチャネル上でこのクローズを()()しないとあなたが短いタイムアウトを指定したとしても、非常に長い時間です。

+0

これは私のために働いた – Pompair

0

私もこの問題に気付きました。 私のコードは、もともとこのように見えたになります。

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

私は、このコードは20 secondstoの実行を取ったことに気づきました。

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

これは、それが取る長い時間は、クライアントのインスタンスのコンテキストを配置していることを信じるように私をリード:私は、このようなチャネルの工場を閉鎖することを決めました。

私はこの解決策をより良く扱う3つの方法があると考えます。

最初に、セッションを終了するクライアントを管理する関数を作成します。この方法では、サービスのシャットダウンが計画される前にそのメソッドを呼び出すことができ、シャットダウン時間が短縮されます。

2つ目は、非同期的に閉じて、接続が終了している間に他の処理を実行することです。

3つ目は、クライアントがセッションを終了できるように(特にクライアントとサービスの両方を制御している場合)、接続を閉じるときにクライアントにプログラムして、サービスを正常かつ迅速にシャットダウンすることです。