2011-06-17 9 views
7

私たちはdozon以上のwcfサービスを持ち、TCPバインディングを使用して呼び出されています。コード内のさまざまな場所で同じwcfサービスへの呼び出しがたくさんあります。WCFプロキシクライアントの作成に時間がかかり、キャッシュまたはシングルトンのソリューションが作成されます

AdminServiceClient client = FactoryS.AdminServiceClient(); //時間がかかります。 (0120) client.Close();

私はクライアントをキャッシュしたり、シングルトンから生成したいと思っています。私はいくつかの時間を節約することができるように、それは可能ですか?

thx

+0

プロキシを使用しているアプリケーションの種類 - スマートクライアントまたはウェブ? –

答えて

8

はい、可能です。プロキシオブジェクトをアプリケーション全体に見えるようにすることができます。または、シンプルさのためにシングルトンクラスにラップすることができます(私の優先オプション)。ただし、サービスのプロキシを再利用する場合は、チャネルの障害を処理する必要があります。

最初に、再利用するプロキシ(またはプロキシ)のインスタンスを保持するシングルトンクラス/キャッシュ/グローバル変数を作成します。

プロキシを作成するとき、あなたは内部チャネル

proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyFaulted); 

には障害発生イベントをサブスクライブし、その後ProxyFaultedイベントハンドラ内で、いくつかの再接続コードを配置する必要があります。 Faultedイベントは、サービスがドロップするか、アイドル状態だったために接続がタイムアウトすると発生します。 faultedイベントは、コンフィグレーションファイル内のバインディングでreliableSessionが有効になっている場合にのみ発生します(指定されていない場合、このデフォルトはnetTcpBindingで有効になります)。

編集:プロキシチャンネルを常に開いたままにしたくない場合は、チャンネルを使用するたびにチャンネルの状態をテストし、フォルトがあればプロキシを再作成する必要があります。チャネルに障害が発生すると、新しいチャネルを作成することはできません。

Edit2:チャネルを開いたままにして閉じるときの負荷の唯一の違いは、キープアライブパケットがサービスに送信され、たびに肯定応答されることです(これはチャネルフォルトイベントの背後にあります)。 100人のユーザーが、これが問題になるとは思わない。

もう1つの方法は、プロキシの作成を使用ブロックの内側に置くことです。ここでは、ブロックの最後(つまり、considered bad practice)でクローズ/廃棄されます。通話後にチャンネルを閉じると、サービスがまだ処理を終了していないため、アプリケーションがハングすることがあります。実際、サービスの呼び出しが非同期であったり、メソッドのサービス契約が一方向であったりしても、サービスが終了するまでチャンネル終了コードはブロックされます。ここで

はあなたが必要なものの裸の骨を持っている必要があり、単純なシングルトンクラスです:

public static class SingletonProxy 
{ 
    private CupidClientServiceClient proxyInstance = null; 
    public CupidClientServiceClient ProxyInstance 
    { 
     get 
     { 
      if (proxyInstance == null) 
      { 
       AttemptToConnect(); 
      } 
      return this.proxyInstance; 
     } 
    } 

    private void ProxyChannelFaulted(object sender, EventArgs e) 
    { 
     bool connected = false; 
     while (!connected) 
     { 
      // you may want to put timer code around this, or 
      // other code to limit the number of retrys if 
      // the connection keeps failing 
      AttemptToConnect(); 
     } 
    } 

    public bool AttemptToConnect() 
    { 
     // this whole process needs to be thread safe 
     lock (proxyInstance) 
     { 
      try 
      { 
       if (proxyInstance != null) 
       { 
        // deregister the event handler from the old instance 
        proxyInstance.InnerChannel.Faulted -= new EventHandler(ProxyChannelFaulted); 
       } 

       //(re)create the instance 
       proxyInstance = new CupidClientServiceClient(); 
       // always open the connection 
       proxyInstance.Open(); 

       // add the event handler for the new instance 
       // the client faulted is needed to be inserted here (after the open) 
       // because we don't want the service instance to keep faulting (throwing faulted event) 
       // as soon as the open function call. 
       proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyChannelFaulted); 

       return true; 
      } 
      catch (EndpointNotFoundException) 
      { 
       // do something here (log, show user message etc.) 
       return false; 
      } 
      catch (TimeoutException) 
      { 
       // do something here (log, show user message etc.) 
       return false; 
      } 
     } 
    } 
} 

私はそれが役立ちます:)

+0

@リチャードオンリーウェブ。 – Techmaster

+0

@Franchescaあなたがコード/参照でもう少し説明できるなら。 100人のユーザーがウェブサイトにアクセスするため、チャンネルが常に開いているときと閉じているときのメリット/デメリットは何ですか? Thx – Techmaster

+0

私はこの情報を追加するために私の答えを編集します:) – Franchesca

2

私の経験では、あたりにチャネルをクローズ/作成を望みますコールベースはほとんどオーバーヘッドを追加しません。 this Stackoverflow questionをご覧ください。それはシングルトンの質問そのものではなく、あなたの問題に関連しています。通常、チャンネルを終了すると、チャンネルを開いたままにしたくない場合があります。

まだお持ちでない場合は、reusable ChannelFactory implementationを使用して、まだパフォーマンスに問題があるかどうかをご確認ください。

関連する問題