2013-05-08 19 views
5

私は困惑しています。おそらく、誰かが私が観察しているWCFのクライアントの振る舞いについていくつかの光を当てることができます。WCFの使用、終了、拡張子

WCFサンプルを使用して、私はWCFクライアント/サーバー通信のさまざまなアプローチを試し始めました。 1Mテストリクエストを並行して実行している間、私はSysInternals TcpViewを使って開いているポートを監視していました。

  1. あなたのことを行う、クライアントを作成し、GCがあなたのことを行う
  2. よりも、使用してブロック内のクライアントを作成します
  3. それを収集してみましょう:今、クライアントを呼び出すために、少なくとも4つの異なる方法があります。
  4. あなたのもの
  5. は、クライアントまたはチャネルを作成し、しかし、私の知る限り、今だけのオプション2-4をあなたのもの

を行うためにWCF Extensionsを使用しないよりも、使用してブロック内の工場からクライアントチャネルを作成します。明示的に呼び出すclient.Close()。実行中、TIME_WAIT状態のポートが多く残っています。 GCに依存しているため、オプション1が最悪のシナリオになると思います。しかし、私の驚いたことに、それはすべての中で最もクリーンであるように見えます。つまり、残っている港は残っていません。

私には何が欠けていますか?

UPDATE:ソースコード

private static void RunClientWorse(ConcurrentBag<double> cb) 
    { 
     var client = new CalculatorClient(); 
     client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service"); 
     RunClientCommon(cb, client);       
    } 

    private static void RunClientBetter(ConcurrentBag<double> cb) 
    { 
     using (var client = new CalculatorClient()) 
     { 
      client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service"); 
      RunClientCommon(cb, client); 
     } 
    } 

    private static void RunClientBest(ConcurrentBag<double> cb) 
    { 
     const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service"; 
     var address = new EndpointAddress(Uri); 
     //var binding = new NetTcpBinding("netTcpBinding_ICalculator"); 
     using (var factory = new ChannelFactory<ICalculator>("netTcpBinding_ICalculator",address)) 
     { 
      ICalculator client = factory.CreateChannel(); 
      ((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60); 
      RunClientCommon(cb, client); 
     } 
    } 

    private static void RunClientBestExt(ConcurrentBag<double> cb) 
    { 
     const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service"; 
     var address = new EndpointAddress(Uri); 
     //var binding = new NetTcpBinding("netTcpBinding_ICalculator"); 
     new ChannelFactory<ICalculator>("netTcpBinding_ICalculator", address).Using(
      factory => 
       { 
        ICalculator client = factory.CreateChannel(); 
        ((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60); 
        RunClientCommon(cb, client); 
       }); 
    } 
+3

あなたはいくつかのソースコードがありません...ユニットテストを見ることができますか? –

+0

http://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue-使用ブロックはWCFで問題を引き起こす可能性があります。 – TrueWill

+0

リンクをありがとう、面白いですが、GCがなぜTIME_WAITを残しているのかをまだ説明していませんが、client.Close()はそれを説明していません。 – Darek

答えて

1

私は、私が思うに、それを考え出しました。 GCは、ClientBaseでDisposeを呼び出さない。そのため、接続はTIME_WAIT状態のままになりません。だから私は、同じパターンに従うことを決定し、新しいWCF拡張を作成しました:

public static void UsingAbort<T>(this T client, Action<T> work) 
     where T : ICommunicationObject 
    { 
     try 
     { 
      work(client); 
      client.Abort(); 
     } 
     catch (CommunicationException e) 
     { 
      Logger.Warn(e); 
      client.Abort(); 
     } 
     catch (TimeoutException e) 
     { 
      Logger.Warn(e); 
      client.Abort(); 
     } 
     catch (Exception e) 
     { 
      Logger.Warn(e); 
      client.Abort(); 
      throw; 
     } 
    } 
} 

この方法は、それは単に代わりにそれを閉じるの接続を中止しますリクエストの終了時。

+0

新しいパターンの問題は、Abort()がクライアントのシャットダウンをサービスに通知しないことです。 tryブロック内の開いている接続でClose()を呼び出さないと、タイムアウトするまでサーバー上で接続を開いたままにします。推奨読書:http://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue – ErnieL

+0

私はそれが@ErnieLのケースだとは思わない。 Microsoftの文書では、Abort()はClientBase オブジェクトを現在の状態から閉じた状態に直ちに移行させます。これは、サーバー側をシャットダウンするポートによって確認されたようです。何か不足していますか? – Darek

+0

文書では、Abort()が「immediate」で、Close()が「graceful」であると言っているのが好きです。例:http://msdn.microsoft.com/en-us/library/ms195520.aspxあなたのパターンは決してClose()を呼び出すことはなく、Dispose()はAbort()を呼び出すのではなく、Close()を呼び出すことがよく文書化されています。だからあなたのパターンが正しい場合、なぜインターフェイスのClose()は何ですか? – ErnieL