2010-01-14 14 views
4

J'écris des tests d'acceptation pour valider un système et son accès aux données se fait à travers des appels de service Web.Regroupement d'appels de service Web .NET?

Malheureusement, parce que je fais tant d'appels, si vite, je lance dans l'erreur suivante

System.Net.Sockets.SocketException: Une seule utilisation de chaque adresse de socket (protocole/adresse réseau/port) est normalement autorisé

J'ai localement mis en cache autant d'appels que possible, mais ce n'est pas suffisant. Je ne peux pas simuler ou me moquer de ces appels. Ils doivent être réels pour que ce niveau de tests soit valide.

Existe-t-il un moyen de regrouper les appels de service Web fréquents?

Ou de vérifier si une connexion peut être établie au service avant de tenter l'appel, et attendre jusqu'à ce qu'un socket disponible existe?

En production, les appels ne sont jamais effectués à cette vitesse, donc le problème ne se pose pas ... mais il serait bien d'avoir du code en place pour permettre aux tests de fonctionner, et de limiter ou de partager les connexions .

Merci

+0

Utilisez-vous les services WCF ou les anciens services ASMX? Comment faites-vous les appels? Comment les cachez-vous? –

+1

Exécutez-vous ce test sur un serveur distant ou sur le serveur Web hébergeant le service? Assurez-vous d'exécuter ces tests à distance. – jwmiller5

+0

@John, Ils sont vieux ASMX.La mise en cache se fait sur les méthodes qui font l'appel, bref, ils gardent la trace des appels et gardent le résultat en mémoire, et au lieu d'appeler le web-service une seconde fois avec les mêmes paramètres, il renvoie l'objet en mémoire . – CaffGeek

Répondre

2

Il s'avère qu'un collègue avait déjà une solution qui était utilisée sur notre site e-com. Vous venez d'hériter de votre service Web, remplacez la fonction GetWebRequest avec des paramètres différents et vous avez terminé.

class SafeMyWebService : MyWS.Service 
{ 
    private static int _lastBindPortUsed; 

    protected override WebRequest GetWebRequest(Uri uri) 
    { 
     var webreq = base.GetWebRequest(uri) as HttpWebRequest; 

     webreq.KeepAlive = true; 
     webreq.ProtocolVersion = HttpVersion.Version10; 
     webreq.ServicePoint.MaxIdleTime = 10 * 1000; // milliseconds 
     webreq.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback); 
     webreq.Timeout = 2000; 
     webreq.ConnectionGroupName = "MyConnectionGroupName"; 

     return webreq; 
    } 

    public static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount) 
    { 
     int port = Interlocked.Increment(ref _lastBindPortUsed); 
     Interlocked.CompareExchange(ref _lastBindPortUsed, 5001, 65534); 

     return remoteEndPoint.AddressFamily == AddressFamily.InterNetwork 
      ? new IPEndPoint(IPAddress.Any, port) 
      : new IPEndPoint(IPAddress.IPv6Any, port); 
    } 

} 

Je suppose qu'il utilise plus de ressources, mais il n'échoue pas.

1

Le MSDN article Avoiding TCP/IP Port Exchastion recommande les approches suivantes

  • Augmenter le nombre de ports éphémères disponibles via le registre (à savoir les ports alloués sur le client pour appeler le webservice
  • Réduire le délai d'attente TCP/IP pour libérer les ports plus rapidement (encore une fois via le registre)

Vous devriez également chec k que vous fermez les connexions correctement après chaque appel dans le démontage du test. Alternativement, si vous ne voulez pas faire de changements de configuration, vous pouvez analyser la plage de ports éphémères et s'il n'y a pas de ports libres, mettez en pause et attendez que certains soient libérés. L'article 'Detecting the next available, Free TCP port' a un exemple de code qui pourrait être adapté à cet effet.

+0

L'appel de service Web utilise une instruction "using" et, par conséquent, il ferme et dispose correctement. Le problème est que Windows ne ferme pas le socket immédiatement (le timeout). Donc, même si vous le fermez, ce n'est pas vraiment fermé, et ils deviennent épuisés. Je préfèrerais NE PAS faire de changements au système car ces tests devraient pouvoir fonctionner n'importe où ... Et changer les paramètres du système pour augmenter les ports éphémères, ou réduire le délai d'attente ne fait que retarder le problème, il ne le résout pas. – CaffGeek

+0

@Chad: Ajout d'une section vous suggérant de parcourir la plage éphémère pour vérifier s'il y a des ports libres (et inclus un lien vers un exemple de code). Cela devrait vous permettre de revenir sur les tests sans nécessiter l'utilisation d'exceptions. –

0

Une solution simple serait de ralentir vos tests en faisant dormir votre thread pendant une courte période; plus rapide que dans la production, mais plus court que celui utilisé dans tous les ports.

Aucun changement dans l'application ou le système.

+0

@Jim, j'ai effectivement mis en œuvre cela. Mais d'une manière moins qu'idéale. J'ai un do/while enveloppant l'appel. Si une exception SocketException est levée, je place un drapeau "hasSocketException" à true et boucle jusqu'à ce qu'il soit à nouveau faux. Lequel est défini avant chaque tentative d'appel. Je préférerais cependant une solution qui n'utilise pas la gestion des exceptions pour faire le contrôle de flux. – CaffGeek

+0

Ce serait plus propre: System.Threading.Thread.Sleep(); Vous pouvez également effectuer les tests en série plutôt qu'en parallèle (pas sûr comment vous le faites). – Jim

+0

@Jim, les tests sont en série. Oh, et il y a un sommeil quand une exception se produit. J'ai oublié de mentionner cela. – CaffGeek