2012-03-19 11 views
2

WCFを使用して他のサービスに接続するWindowsサービスがあります。それらが生存していることをチェックし、これらのサービスが持つエラーメッセージを取得し、これらのレポートを報告します。これは、チャネルファクトリを使用して30秒ごとにチェックされます。チャネルファクトリを使用すると、インターフェイスに準拠するコンフィギュレーション内で見つかったサービスごとにプロキシが作成されます。うまく動作してから数日が経過すると、サーバーは応答しなくなり、「RPC Server Unavailable Error」の報告を開始します。私はそれに接続するためにコンピュータの管理を使用することができ、メモリフットプリントは登るようには見えませんが、サービスを停止すると問題は完全に修正されます。私が使用しているチャンネルファクトリマネージャーを添付しましたが、他に必要なものがあれば教えてください。サービスチャネルが正しく解放されていない可能性はありますか?これを診断するには何ができますか?誰もこれを前にして来たのですか?WindowsサービスがWCFを呼び出すことによって発生する「RPCサーバーで利用できないエラー」を診断する

public class ChannelFactoryManager : IDisposable 
{ 
    private static Dictionary<Tuple<Type, string>, ChannelFactory> _factories = new Dictionary<Tuple<Type, string>, ChannelFactory>(); 
    private static readonly object _syncRoot = new object(); 

    public virtual T CreateChannel<T>() where T : class 
    { 
     return CreateChannel<T>("*", null); 
    } 

    public virtual T CreateChannel<T>(string endpointConfigurationName) where T : class 
    { 
     return CreateChannel<T>(endpointConfigurationName, null); 
    } 

    public virtual T CreateChannel<T>(string endpointConfigurationName, string endpointAddress) where T : class 
    { 
     T local = GetFactory<T>(endpointConfigurationName, endpointAddress).CreateChannel(); 
     ((IClientChannel)local).Faulted += ChannelFaulted; 
     return local; 
    } 

    protected virtual ChannelFactory<T> GetFactory<T>(string endpointConfigurationName, string endpointAddress) where T : class 
    { 
     lock (_syncRoot) 
     { 
      ChannelFactory factory; 
      if (!_factories.TryGetValue(new Tuple<Type, string>(typeof(T), endpointConfigurationName), out factory)) 
      { 
       factory = CreateFactoryInstance<T>(endpointConfigurationName, endpointAddress); 
       _factories.Add(new Tuple<Type, string>(typeof(T), endpointConfigurationName), factory); 
      } 
      return (factory as ChannelFactory<T>); 
     } 
    } 

    private ChannelFactory CreateFactoryInstance<T>(string endpointConfigurationName, string endpointAddress) 
    { 
     ChannelFactory factory = null; 
     if (!string.IsNullOrEmpty(endpointAddress)) 
     { 
      factory = new ChannelFactory<T>(endpointConfigurationName, new EndpointAddress(endpointAddress)); 
     } 
     else 
     { 
      factory = new ChannelFactory<T>(endpointConfigurationName); 
     } 
     factory.Faulted += FactoryFaulted; 
     factory.Open(); 
     return factory; 
    } 

    private void ChannelFaulted(object sender, EventArgs e) 
    { 
     IClientChannel channel = (IClientChannel)sender; 
     channel.Abort(); 
    } 

    private void FactoryFaulted(object sender, EventArgs args) 
    { 
     ChannelFactory factory = (ChannelFactory)sender; 
     factory.Abort();    

     Type[] genericArguments = factory.GetType().GetGenericArguments(); 
     if ((genericArguments != null) && (genericArguments.Length == 1)) 
     { 
      Type type = genericArguments[0]; 
      string endPointName = factory.Endpoint.Name; 
      Tuple<Type, string> key = new Tuple<Type, string>(type, endPointName); 

      if (_factories.ContainsKey(key)) 
      { 
       _factories.Remove(key); 
      } 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      lock (_syncRoot) 
      { 
       foreach (Tuple<Type, string> type in _factories.Keys) 
       { 
        ChannelFactory factory = _factories[type]; 
        try 
        { 
         factory.Close(); 
         continue; 
        } 
        catch 
        { 
         factory.Abort(); 
         continue; 
        } 
       } 
       _factories.Clear(); 
      } 
     } 
    } 
} 

おかげ ロブ

+0

あなたのディスポーザルコードが期待どおりに機能していないように、あなたが説明している問題は確かに聞こえます。この[Gordian Knot](http://en.wikipedia.org/wiki/Gordian_knot)をカットしたい場合は、静的コレクションを取り除き、必要に応じて各WCFクライアントtry/catchパターン内で各サービスプロキシをインスタンス化してください> try> call> close> catch> abort)を選択します。パフォーマンスは低下しますが、少なくとも、あなたが今行っているようなネットワークリソースが漏れていないかどうかを判断することができます:) –

+0

ありがとうございました。パフォーマンスはそれほど問題にならないはずです。そのようなものはもっと良い賭けになるでしょう。 – bobwah

答えて

1

あなたが必要なルートとしてインスタンス化サービスプロキシで行く場合は、このSO questionで答えはいくつかのオプションとプロキシインスタンスの処分のための理論的根拠を与えます。基本的なスタートとして、私はお勧め:

//Your client type could be ICommunicationObject or ClientBase: 
var client = new YourServiceProxyType(); 
try { 
    var result = client.MakeCall(); 
    //do stuff with result... 

    //Done with client. Close it: 
    client.Close(); 
} 
catch (Exception ex) { 
    if (client.State != System.ServiceModel.CommunicationState.Closed) 
     client.Abort(); 
} 

良いWCFプロキシ処分パターンを設計する上での基本的な問題は、MicrosoftのWCFのチームは、このように管理されていないのリリースを防止し、例外を投げることができる方法で処分を実施することを決定したということですAbort()が呼び出されるか、プロキシインスタンスが完全にガベージコレクションされるまで彼らはフレームワークを書いて彼らが選択をするようにしましたが、残念ながら私たちはその結果に苦しんでいなければなりません。

+0

ありがとう私はしばらくそれをして、これを正解とマークします。私はIoCと単体テストのために、ある時点でこれを抽象化したいと思います。少なくとも、私はその問題が処分であり、それを修正できることを知っています。 – bobwah

関連する問題