2012-03-19 4 views
2

J'ai un service Windows qui utilise WCF pour se connecter à d'autres services. Il vérifie qu'ils sont en vie, reçoit les messages d'erreur de ces services et les signale. Ceci est vérifié toutes les 30 secondes à l'aide d'une fabrique de canaux où des proxys sont créés pour chaque service trouvé dans la configuration conforme à une interface. Après quelques jours de fonctionnement, le serveur ne répond plus et commence à signaler une erreur "Erreur du serveur RPC non disponible". Je peux utiliser la gestion de l'ordinateur pour me connecter à elle et l'impression de pied de mémoire ne semble pas grimper, mais si j'arrête le service, il résout complètement le problème. J'ai attaché le directeur d'usine de canal que j'utilise si n'importe quoi d'autre est nécessaire s'il vous plaît faites le moi savoir. Se pourrait-il que les canaux de service ne soient pas libérés correctement? Que puis-je faire pour diagnostiquer cela? Est-ce que quelqu'un à déjà rencontré cela avant?Diagnostique "Erreur non disponible du serveur RPC" provoquée par le service Windows appelant WCF

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

Merci Rob

+0

Le problème que vous décrivez a certainement l'air de ne pas fonctionner comme prévu. Si vous voulez couper ce [noeud gordien] (http://en.wikipedia.org/wiki/Gordian_knot), débarrassez-vous des collections statiques et instanciez simplement chaque proxy de service selon les besoins dans un bon modèle try/catch de client WCF (create> try> call> close> catch> abort) de votre choix. Les performances vont en souffrir mais au moins, vous pouvez compter sur les ressources du réseau qui ne fuient pas comme vous le feriez maintenant :) –

+0

Ok, merci, je vais essayer. La performance ne devrait pas être un problème, alors peut-être que quelque chose comme ça serait un meilleur pari. – bobwah

Répondre

1

Si vous allez avec les procurations de service instantier itinéraire nécessaire, les réponses dans cette SO question donnent certaines options et la justification de la disposition de l'instance proxy. En début de base que je vous recommande:

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

La question fondamentale dans la conception d'un bon modèle d'élimination proxy WCF est que l'équipe WCF à Microsoft a décidé de mettre en œuvre Dispose d'une manière qui peut lancer des exceptions empêchant ainsi la libération non géré ressources jusqu'à ce que Abort() soit appelé ou que l'instance de proxy soit complètement récupérée. Ils ont écrit le cadre pour qu'ils puissent faire les choix, malheureusement nous devons en subir les conséquences.

+0

Merci d'avoir fait cela pour le moment et je vais marquer cela comme une réponse correcte. J'aimerais en faire abstraction à un moment ou à un autre pour tester l'IoC et l'unité lorsque j'y arriverai. Je sais que le problème est l'élimination et que je peux y remédier. – bobwah

Questions connexes