2010-01-29 5 views
0

Mon programme effectue des requêtes Web, mais parfois je vais avoir une exception disant que le serveur a fermé la connexion. Quand cela arrive, je dois rouvrir une connexion.Try ... Catch et requêtes HTTP

Dois-je mettre le code dans un essai ... attraper? Si la connexion est fermée à l'essai, rouvrez-la dans la capture? Mais mon problème serait, et si les serveurs ferment la connexion ouverte dans le catch?

Voici mon code pour le moment.

public String postRequest(String pD, String url) 
    { 
     String postData = pD; 

     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
     byte[] buffer = Encoding.ASCII.GetBytes(postData); 

     /** Set the headers **/ 
     request.ContentType = "application/x-www-form-urlencoded"; 
     request.ContentLength = buffer.Length; 
     request.ServicePoint.Expect100Continue = false; 
     request.Method = "post"; 

     Stream PostData = request.GetRequestStream(); 
     PostData.Write(buffer, 0, buffer.Length); 
     PostData.Close(); 

     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
     Stream responseStream = response.GetResponseStream(); 
     StreamReader read = new StreamReader(responseStream); 

     String line; String source = ""; 
     while ((line = read.ReadLine()) != null) source += line; 
     return source; 
    } 
+0

Ou, serait-il préférable de vérifier l'exception, et que la méthode s'appelle l'exception est levée? –

Répondre

2

Essayez Execute-Around method. Cet objet prend un délégué qui prend le travail à effectuer en tant que bloc de code/délégué. objet.Exécuter aurait

  • avoir un pré-bloc qui permettrait de vérifier si le conn est toujours ouvert. Dans le cas contraire, une nouvelle tentative x fois jusqu'à ce qu'une connexion soit établie
  • appeler le délégué
  • Nettoyons (laisser la conn ouverte si vous jugez bon)

Mise à jour: Ok. (J'ai répondu rapidement hier). Ma réponse précédente suppose qu'il existe un moyen de savoir si la connexion est toujours active/ouverte. Mais si mes pouvoirs d'inférence de problème sont corrects, le problème est que vous ne pouvez pas être sûr que le conn est actif, sauf si vous l'utilisez réellement et recevez une exception.

Je pensais à ce sujet pendant un certain temps et peut-être que je suis influencé par le livre que je suis en train de lire ... Je pense que ce dont vous avez besoin est l'équivalent d'une approche ruby ​​sauvetage-n-retry

begin 
    # do stuff for sending a request 
rescue ConnectionClosedError 
    # handle the error to ensure that a retry has a chance of succeeding 
    retry 
end 

Maintenant, je ne pense pas que vous ayez ce natif en C#, mais vous pouvez écrire un script assez proche. avec un goto (boucliers!). C'est l'un des rares cas où goto est simpler-n-clean. Un exemple serait

static void Main() 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     PostRequest(); 
    } 
} 
private static void PostRequest() 
{ 
    Console.Write("Start..."); 

Retry: 
    try 
    { 
     CodeThatMightThrowAnException(); 
     Console.WriteLine("Done!"); 
    } 
    catch (ConnectionClosedException e) 
    { 
     Console.Write("Error! Attempt to reconnect..."); 
     goto Retry; 
    } 
} 

static Random _randomizer = new Random(); 
private static void CodeThatMightThrowAnException() 
{ var randomEvent = _randomizer.Next(20); 
    Console.Write("- {0} -", randomEvent); 
    if (randomEvent % 3 == 0) 
     throw new ConnectionClosedException("Server dropped me!"); 
} 

Sortie:

Start...- 10 -Done! 
Start...- 16 -Done! 
Start...- 9 -Error! Attempt to reconnect...- 14 -Done! 
Start...- 0 -Error! Attempt to reconnect...- 3 -Error! Attempt to reconnect...- 
19 -Done! 
Start...- 15 -Error! Attempt to reconnect...- 6 -Error! Attempt to reconnect...- 
5 -Done! 
Start...- 2 -Done! 
Start...- 14 -Done! 
Start...- 13 -Done! 
Start...- 14 -Done! 
Start...- 19 -Done! 

Note: Bien sûr, vous devez garder une trace de l'état requis et protéger aussi contre d'entrer dans une boucle infinie de nouvelle tentative.

+0

La méthode que j'ai est contenue dans une classe HTTP personnalisée pour gérer les demandes get et post. N'est-ce pas le même genre de chose? –

+0

@James - voir mise à jour. HTH – Gishu

1

Demandez à l'appelant de postRequest d'effectuer l'opération try/catch et de décider s'il doit réessayer. À l'intérieur de postRequest, assurez-vous que vous nettoyez correctement même si une exception est levée, par exemple. vos flux doivent être enveloppés dans une clause using().

+0

Pouvez-vous imbriquer la clause using?J'ai 3 flux dans mon code. Et aurais-je besoin de fermer manuellement les flux même si j'utilise la clause using? –

+0

@ James Jeffery: Oui imbrique using-instructions est correct (si elle échoue l'interface IDisposable n'est pas implémentée correctement dans l'un des Streams que vous utilisez). Vous pouvez même les imbriquer comme ceci 'using (...) using (...) {.. font des trucs ..}'. – Skurmedel

2

Je voudrais simplement boucle jusqu'à atteindre une nouvelle tentative limite spécifiée:

for(int retryCount = 0; retryCount < 5; retryCount++) { 
    try { 
     String postData = pD; 
     ... 
     return source; 
    } catch(Exception e) { 
     // perhaps log exception? 
    } 
} 

Comme nos a déjà signalé, vous devez vous assurer que vos ressources sont libérées correctement.