2011-12-16 5 views
5

Je travaille sur une application winform qui va accéder à un service WCF auto-hébergé en tant que service Windows. J'utilise ChannelFactory à la place de la référence de service. J'ai réussi à connecter et à appeler le service WCF. Le problème est lorsque je laisse l'application rester inactive pendant 20 minutes et ensuite essayer de faire un autre appel. Le message d'erreur suivant s'affiche:Meilleure pratique avec WCF ChannelFactory et délai de connexion

"La connexion au socket a été annulée, ce qui peut être dû à une erreur de traitement du message ou à un dépassement du délai de réception par l'hôte distant ou à un problème de ressource réseau sous-jacent. 00: 00: 59.9489970 '. " Je recherche la meilleure pratique pour gérer la connexion. J'ai actuellement créé une fonction appelée PrepareWCFConnection (voir ci-dessous) qui vérifie l'état du canal et le ChannelFactory. J'appelle cette méthode avant de faire des appels aux services de la WCF. Y a-t-il une meilleure façon de gérer cela?

 public bool PrepareWCFConnection() 
    { 
     if ((channelFactory == null) || 
      (channelFactory.State == CommunicationState.Faulted) || 
      (channelFactory.State != CommunicationState.Opened)) 
     { 
      channelFactory = new ChannelFactory<IService1>(new NetTcpBinding(), endpointAddress); 
     } 


     if ((proxy == null) || 
      (((IClientChannel)proxy).State == CommunicationState.Faulted) || 
      (((IClientChannel)proxy).State != CommunicationState.Opened)) 
     { 
      proxy = channelFactory.CreateChannel(endpointAddress); 
      ((IClientChannel)proxy).Open(); 
     } 

     return true; 
    } 
+0

Plus de tests du code ci-dessus ont prouvé que cela ne fonctionnait pas. Le ChannelFactory et le canal sont ouverts mais je reçois toujours cette erreur après avoir laissé le système tourner au ralenti: la connexion du socket a été annulée. Cela peut être dû à une erreur de traitement de votre message ou à un dépassement de délai de réception de l'hôte distant ou à un problème de ressource réseau sous-jacent. Le délai d'attente de la socket locale était '00: 00: 59.9479970'. – econner

+1

Voici un lien de MSDN qui montre la création du canal et de la chaîne, effectue les appels et ferme le canal, puis ferme la fabrique de canaux. Cependant, si vous utilisez des crédits pour vous authentifier, ne fermeriez-vous pas le canal après chaque appel de méthode et recréeriez le canal avant que chaque méthode soit coûteuse en ressources et en temps? http://msdn.microsoft.com/en-us/library/ms734681.aspx – econner

+0

Après avoir testé plus, je commence d'abord l'appel au service WCF avec PrepareWCFConnection() ... puis appelez ma méthode de service, puis appelez ((IClientChannel) proxy) .Close(); Ceci ferme la connexion de canal et crée ensuite un nouveau canal pour chaque appel de méthode. Est-ce la meilleure pratique? – econner

Répondre

4

Si vous souhaitez réutiliser un canal existant, vous devez garder en vie le canal par pinger le service tous les 9 minutes.I pensent que le délai de réception par défaut est de 10 minutes, de sorte que le canal sera déconnecté si elle est maintenue Vous pouvez utiliser des sessions fiables pour garder les canaux en vie. Si vous n'avez pas besoin de rappel sur le même canal, il est préférable de fermer le canal une fois que vous avez terminé et de recréer un nouveau canal pour chaque opération de service.Il n'est pas cher de créer des canaux.Vous pouvez mettre en cache le usine de canal, mais créer des canaux pour chaque appel.

+1

bon point: _Vous pouvez mettre en cache la fabrique de canaux, mais créer des canaux pour chaque appel_. – baraban

1

Je sais que cette question est assez ancienne maintenant mais je vois qu'elle n'a pas vraiment eu de réponse. Il y a deux délais d'attente (enfin seulement 1 si vous n'utilisez pas de messagerie fiable), vous devriez vous préoccuper de l'expiration des canaux. Du côté du service, vous avez le "ReceiveTimeout" qui est déclenché si aucun message d'application n'est reçu dans le délai imparti. La valeur par défaut pour ce délai est de 10 minutes.

Il existe également le paramètre "InactivityTimeout" qui n'est utilisé que si "ReliableSession" est activé. Ce délai est la durée maximale pendant laquelle le canal permet à l'autre interlocuteur de n'envoyer aucun message avant de le perturber.

Pour augmenter la durée de vie de votre chaîne, je vous recommande d'activer "ReliableSession", puis de définir votre "ReceiveTimeout" & "InactivityTimeout" sur une valeur plus élevée. ReliableSession maintient le canal en vie en envoyant des ILM (messages au niveau de l'infrastructure) comme keep-alive (les ACK sont également envoyés). Si un message persistant ou un message ALM (niveau d'application) n'est pas reçu avant l'expiration du délai "InactivityTimeout", le canal sera défaillant.

En outre, si un message ALM (niveau d'application) n'a pas été reçu avant l'expiration du délai "ReceiveTimeout", le canal sera défaillant. Par conséquent, il est recommandé d'augmenter les deux temporisations à la même valeur OU de définir la valeur "ReceiveTimeout" sur une valeur supérieure à "InactivityTimeout".

Une remarque de côté, la définition de "ReceiveTimeout" n'aura aucun effet lorsqu'elle est définie du côté client, elle est uniquement un délai d'expiration côté service. Mais lorsque vous utilisez ReliableSession sur le côté service, le client doit également mettre en œuvre comme ceci:

NetTcpBinding binding = new NetTcpBinding 
     { 
      ReliableSession = { Enabled = true },    
      SendTimeout = TimeSpan.FromMinutes(1) 
     }; 

     binding.ReliableSession.InactivityTimeout = TimeSpan.Parse("24.20:31:23.6470000"); 

Et l'application.config sur le côté service ressemblerait à quelque chose comme ceci:

<bindings> 
    <netTcpBinding> 
     <binding name="netTestTcpBinding" 
       receiveTimeout="24.20:31:23.6470000"> 
     <reliableSession inactivityTimeout="24.20:31:23.6470000" 
         enabled="true" /> 
     </binding> 
    </netTcpBinding> 
    </bindings> 
<services> 
    <service> 
    <endpoint address="IServiceContract" 
       binding="netTcpBinding" 
       bindingConfiguration="netTestTcpBinding" 
       name="serviceContractTcpBinding"/> 
    <host> 
     <baseAddresses> 
      <add baseAddress="net.tcp://localhost:12001/" /> 
     </baseAddresses> 
    </host> 
    </service>     
</services> 
0

Une solution assez simple de réutiliser votre canal, sans vote ou faire des choses extravagantes, il est juste prendre soin du dernier appel à votre chaîne et vérifiez la WCFC. Binding.ReceiveTimeout afin de le régénérer si nécessaire, quelque chose comme:

TimeSpan timeSpan = DateTime.Now - LastCallTime; 
    if (timeSpan.TotalSeconds > wcfC.Binding.ReceiveTimeout.TotalSeconds || wcfC.State != CommunicationState.Opened) 
    { 
     wcfC.Abort(); 
     wcfC = new WCFChannel(); 

    }  
    LastCallTime = DateTime.Now; 
Questions connexes