2012-02-14 20 views
3

.NETアプリケーションは2つのAppDomainsを使用します。セカンダリドメインは、メインのappdomainで作成されたLoggerオブジェクトにアクセスする必要があります。NamedPipe WCFサービスを使用するとCommunicationObjectForted

このロガーは、名前付きパイプバインディングを使用してWCFサービスを介して公開されています。

これは私がこのサービスのために、「クライアント」を作成する方法である:

 private void InitLogger() 
     {  
      if (loggerProxy != null) 
      { 
       Logger.Instance.onLogEvent -= loggerProxy.Log; 
      } 

      // Connect to the logger proxy. 
      var ep = new EndpointAddress("net.pipe://localhost/app/log"); 
      var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); 

      //Logger.Debug("Creating proxy to Logger object."); 
      var channelFactory = new ChannelFactory<ILogProvider>(binding, ep); 

      loggerProxy = channelFactory.CreateChannel(); 
      channelFactory.Faulted += (sender, args) => InitLogger(); 
      channelFactory.Closed += (sender, args) => InitLogger(); 

      Logger.Instance.onLogEvent += loggerProxy.Log; 
     } 

最近、我々はランダムCommunicationObjectFaultedExceptionを取得している - 私は、これは、チャネルの時代から私は行方不明です他のいくつかの理由からかにより発生したと仮定。

これは私が(おそらく、私はそれらを適切に使用していない)正常に動作しないように見える休館障害が発生しイベントのハンドリングを追加した理由です。

EDIT:これらのイベントは、提案されているようにFactoryオブジェクトにあります。そのため、これらのイベントはなぜ発生していないのかが説明されています。

私の質問は - これらのエラーを回避するにはどうすればよいですか?

私たちのシナリオでは、アプリケーションの有効期間中いつでもこのチャンネルを開いたままにしておく必要があります。また、このLoggerサービスへのアクセスは常に必要とされます。

このような状況を処理する安全な練習はありますか?

答えて

6

あなたのコードは現在、ChannelFactoryによって生成されたClosed and Faultedイベントを処理していますが、気にする必要があるChannel自体の状態です。

ChannelFactoryは、WCFサービスコントラクトの変換をチャネルランタイムのインスタンスにカプセル化したものです。チャネル(loggerProxy)を正常に作成すると、ChannelFactoryの終了は通信に影響しませんチャンネル - あなたが聞いているイベントは、あなたの問題とは無関係です。 loggerProxy.Logが呼び出されたときにクローズまたはフォルト発生へチャンネル

状態遷移は、彼らがスローされた例外としてLogger.Instanceに表面化するという結果と、このコードに気付かれないだろう、とイベントが、あなたは意志をログに記録しようとしています失われます。

loggerProxy.Logをイベントハンドラとして直接登録する代わりに、例外ハンドラを実装するラッパー関数を登録し、loggerProxy.Logの呼び出しの回りにループを再試行することを検討する必要があります。例外ハンドラで既存のチャネルを閉じて(または失敗した場合は中断して)、適切に廃棄されるようにする必要があります。再試行ループは、チャネルを再初期化し、再度呼び出しを試みる必要があります。

+0

ありがとうございます!すでにこのソリューションを提供していることをご存じのBCLまたはオープンソース実装のクラスがありますか? –

1

私は、(i)タイムアウトと(ii)フォールトイベントをキャッチすることについてコメントします。

まずタイムアウト。デフォルトでは、チャネルは、デフォルトの時間(約10分)の間に通信していなければ障害状態になります。定期的なイベントでチャネルを頻繁にポーズするか、タイムアウトを大きなものにリセットすることができます。

NetNamedPipeBinding binding = new NetNamedPipeBinding(); 

    // Have to set the receive timeout to be big on BOTH SIDES of the pipe, otherwise it gets faulted and can't be used. 
    binding.ReceiveTimeout = TimeSpan.MaxValue; 

    DuplexChannelFactory<INodeServiceAPI> pipeFactory = 
     new DuplexChannelFactory<INodeServiceAPI>(
      myCallbacks, 
      binding, 
      new EndpointAddress(
      "net.pipe://localhost/P2PSN.Node.Service.Pipe")); 

myCallbacksは二重パイプにコールバックを扱うとINodeServiceAPIは私のAPIを記述するインタフェースであるクラスのインスタンスである:次のように私は後者を行います。

第2に、あなたは工場内でイベントが発生することはありません。チャンネル自体でイベントをキャッチすることができます。私は次のコードを使用します。

proxy = pipeFactory.CreateChannel(); 
    if (proxy is IClientChannel) 
    { 
     (proxy as IClientChannel).Faulted += new EventHandler(this.proxy_Faulted); 
    } 

私は気に入らないが、他の場所でStackOverflowから取り上げたものがあります。 IClientChannelインターフェイスを取得するには、System.ServiceModelをインクルードする必要があります。

HTH。

+0

プロキシ側のReceiveTimeoutをMaxValueに設定しても、メッセージを送信してNO MESSAGEを受信するとクライアント側が無期限にブロックされることはありません。 –

+0

チェックアウトする価値があります。私はWindowsサービスとそれを管理するWindowsフォームアプリケーションの間のプロセス間パイプの片側として上記を使用しています。あなたはタイムアウトだけを残して、フォールトをキャッチし、すべてをダウンして新しいチャンネルを作成することができます...しかし、それは極端なようです。確かに再発的な迅速なpingは、DoSが試行される可能性のあるアプリケーションでは、より頻繁に適用される可能性があります。 –

+0

DoSはここでは問題になりません。私はアプリケーション間ドメイン通信を行っています。これはまったくサービスではなく、両方のアプリケーションドメイン間でメソッド呼び出しを一緒にテーピングするための簡単な接着剤です。 –

関連する問題