2009-09-11 15 views
1

J'ai un petit moteur d'hébergement WCF que j'écris qui va créer dynamiquement des ServiceHosts basés sur le fichier .config. L'idée générale est de nous permettre de supprimer des services existants, ainsi que d'ajouter de nouveaux services, à l'exécution sans avoir à mettre tous nos services hors ligne.Conflit de ServiceHost sur l'adresse lors du test de l'unité

J'ai rencontré un problème de test d'unité qui indique que cela peut ne pas être aussi facile que cela puisse paraître. Il semble qu'un seul ServiceHost puisse exister pour n'importe quel point de terminaison donné (même si plusieurs points de terminaison différents pour un service peuvent exister dans un seul ServiceHost). Ce n'est pas un problème normalement, cependant quand un service doit être reconfiguré, l'abaissement du ServiceHost d'origine ne tue pas réellement l'enregistrement pour cette adresse de point de terminaison. Essayer de créer un autre ServiceHost, pour le même service (ce qui signifie que les mêmes critères d'évaluation sont utilisés) échoue à l'exception suivante:

System.InvalidOperationException: The ChannelDispatcher at 'net.pipe://localhost/' with contract(s) '"ITestService"' is unable to open its IChannelListener. ---> 
System.InvalidOperationException: A registration already exists for URI 'net.pipe://localhost/'. 

Je rencontre en fait l'erreur lors de tests unitaires. Les tests exerceront une unité, ce qui ferme complètement le ServiceHosts et héberge le moteur autant qu'il est humainement possible. Puis crée une autre instance du moteur d'hébergement, qui essaie de recréer les mêmes ServiceHosts pour un test différent. Le deuxième test rencontre l'erreur ci-dessus. Je devine que pendant que ServiceHost.Close() a été appelé, cela ne détruit pas réellement l'hôte de service ... ainsi il traîne toujours dans la mémoire. Je ne peux pas dire si le GC nettoie les anciens serveurs ou pas ... le problème persiste sans partir après qu'il se soit produit initialement (du mieux que j'ai pu le déterminer ... J'ai attendu environ 30 minutes jusqu'à présent.)

Mon fichier de configuration pour system.serviceModel est la suivante:

<system.serviceModel> 
    <services> 
     <service name="Campus.Core.ServiceModel.TestServiceStub"> 
     <endpoint   
      address="net.pipe://localhost"   
      binding="netNamedPipeBinding"   
      contract="Campus.Core.ServiceModel.ITestService" 
     /> 
     </service> 
    </services> 
    </system.serviceModel> 
+0

Je suis confronté au même problème. Avez-vous été capable de le résoudre depuis? – Elan

+0

Je suis tombé sur ce problème il y a un an ou deux. Je n'ai plus le code, mais j'ai trouvé un moyen d'héberger le service par programmation via le code, ce qui m'a permis de changer le port lors des tests unitaires. J'espère que cela vous aidera de quelque façon que ce soit. –

Répondre

3

Pour fournir une réponse à cette question, au cas où quelqu'un d'autre a rencontré le problème. 1) Au cours des tests unitaires, si une exception était rencontrée, elle sortirait généralement du code testé avant que le ServiceHost puisse être fermé. Cela a laissé le ServiceHost lié à un point de terminaison particulier. Cela a provoqué l'échec de TOUS les tests suivants qui ont utilisé le même code. Comme je faisais BDD avec SubSpec et xUnit, un seul cas de test (problème en termes BDD) effectuait une seule assertion par test, et un seul cas de test pouvait englober jusqu'à une douzaine d'assertions ou plus.

2) Méfiez-vous du point de terminaison MEX. Le point de terminaison MEX ne peut exister qu'une seule fois par service. Initialement, j'avais créé un endpoint http et net.tcp mex. Cela a toutefois provoqué un problème, car l'instance du point de terminaison MEX démarrée en second lieu a émis une exception. De manière générale, si vous utilisez le point de terminaison MEX, HTTP est le protocole le plus utile à utiliser, à moins qu'un problème d'infrastructure physique ne vous empêche de le faire.En règle générale, l'appel de la méthode Close() sur un ServiceHost le désintelliera complètement, permettant ainsi à toutes les adresses précédemment liées à ses points de terminaison d'être à nouveau utilisables. Parfois, la fermeture peut prendre un certain temps et, dans de rares cas, une exception peut être levée. Si vous exécutez BDD avec SubSpec et que vous suivez la règle de l'assertion unique par test, une exception déclenchée dans un test qui empêche la fermeture de ServiceHosts entraînera l'échec de tous les tests suivants.

1

une solution consiste à ajouter un Guid à l'URL de l'hôte de service chaque fois que vous faites tourner un, et d'utiliser une approche usine qui Les deux font tourner les instances ServiceHost et retournent le canal côté client, afin que le client sache quelle URL utiliser.

échantillon InProcFactory de IDesign utilise cette approche, vous pouvez donc être en mesure de l'utiliser tel quel:

http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=5&tabid=11

Notez que vous devez vous inscrire sur le site de IDesign afin de télécharger l'échantillon, et ils vous enverront l'annonce occasionnelle de l'entraînement et autres, mais ce n'est pas trop.

+0

Nos URL ne peuvent pas être générées automatiquement, car elles sont explicitement définies. Nous utilisons nos URL dans le cadre de notre stratégie de gestion des versions. Nos services sont également utilisés par plusieurs plates-formes, pas seulement .NET, donc nous n'avons pas toujours le contrôle sur les clients. :( – jrista