0

J'ai une application CSharp (CF2.0) pour les terminaux Windows Mobile 6.5. J'ai un thread qui toutes les 1,5 minutes essayent de se connecter à un WebService PHP. J'essaie de lire la réponse de ce WebService PHP avec une méthode ReadToEnd(). Cela fonctionne, mais parfois (aléatoirement) les blocs de routine sur ReadToEnd(). Je ne sais pas pourquoi.Utilisation de StreamReader avec le bloc HttpWebResponse ReadToEnd()

Voici le code:

public static string CallWebServiceProblem(string url, int timeout) 
{ 

    string s = ""; 

    ServicePointManager.DefaultConnectionLimit = 10; 


    _logger.Trace("web service: {0} timeout: {1}", url, timeout); 
    HttpWebRequest wrGETURL = null; 
    try 
    { 
     bool isProblema = url.IndexOf("lsp_r2") >= 0; 
     if (isProblema) 
      _logger.Info("Sono in lsp_r2..."); 

     wrGETURL = (HttpWebRequest)WebRequest.Create(url); 
     wrGETURL.Credentials = CredentialCache.DefaultCredentials; 

     wrGETURL.ReadWriteTimeout = 10000; // Per vedere se sistema un po' i timeout... 
     if (timeout != 0) 
      wrGETURL.Timeout = 3000; // timeout... 

     Stream ojstream = null; 
     StreamReader sr = null; 
     HttpWebResponse httpresponse = null; 

     try 
     { 
      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo GetResponse..."); 

      httpresponse = (HttpWebResponse)wrGETURL.GetResponse(); 

      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo GetResponseStream..."); 

      ojstream = httpresponse.GetResponseStream(); 
      Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 

      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo StreamReader..."); 

      sr = new StreamReader(ojstream, encode); 

      if (isProblema) 
       _logger.Info("lsp_r2: inizio a leggere"); 

      s = sr.ReadToEnd(); 
      if (isProblema) 
      { 
       _logger.Info("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
       System.Diagnostics.Debug.WriteLine("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
#if DEBUG 
       // _logger.Info("lsp_r2: ho letto " + s); 
       System.Diagnostics.Debug.WriteLine("lsp_r2: ho letto " + s); 
#endif 
      } 
     } 
     catch (Exception ex) 
     { 
      _logger.Error("web service: {0} timeout: {1} exception: {2} - {3}", url, timeout, ex.Message, ex.InnerException != null ? ex.InnerException.Message : "??"); 
      throw new Exception(ex.Message); 
     } 
     finally 
     { 

      if (isProblema) 
       _logger.Info("lsp_r2: Concludo..."); 

      if (sr != null) 
      { 
       sr.Close(); 
       sr.Dispose(); 
      } 

      if (ojstream != null) 
      { 
       ojstream.Close(); 
       ojstream.Dispose(); 
      } 

      if (httpresponse != null) 
      { 
       httpresponse.Close(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(ex.Message); 
    } 
    finally 
    { 

    } 

    return s; 

} 

J'utilise cette routine pour un peu de PHP WS dans ma demande, mais je le seul problème avec celui qui renvoie un grand nombre de caractères (peut être 8000 et plus .. .). La chaîne renvoyée par WS est une chaîne qui se termine par CRLF; les valeurs sont séparées par | et les enregistrements sont séparés par § (peut-être ce caractère ASCII un problème ??). Quelque chose comme ceci (cet exemple a un seul enregistrement)

80643 | 882168 | 145 | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 2016-04-04 19: 43: 24 | 1900- 01-01 00: 00: 00 | 1900-01-01 00: 00: 00 | 1900-01-01 00: 00: 00 | 2016-04-04 19: 43: 42 ||||| 2016-04- 04 09: 45: 42 | 08: 45 1TG GALDINO, 8 Milan Ditta: ZEBRE X PROVA() || Int.pr: Orário Continuato | 2016-04-04 10: 45: 42 | V LARGA, Ditta:() | LARGA | Int.co: Orario Continuato || 0 | 2016-04-04 08: 46: 03 | 2016-04-04 19: 43: 42 | 2 || 0 | 0000-00-00 00: 00: 00§

Lorsque le bloc occours, dans mon journal, je vois "lsp_r2: Inizio a leggere" (la ligne avant la ReadToEnd) et je ne vois pas lsp_r2: terminato di leggere (la ligne après la ReadToEnd) .

J'ai essayé également d'utiliser quelque chose comme ça

int totCar = 0; 
while (sr.EndOfStream == false) { 
    int numCar = sr.Peek(); 

    char[] caratteri = new char[numCar]; 

    sr.Read(caratteri, 0, numCar); 

    string newString = new string(caratteri); 
    // Arrivano un sacco di null.. li rimuovo 
    int posNull = newString.IndexOf('\0'); 
    if (posNull >= 0) 
     newString = newString.Substring(0, posNull); 

    s += newString; 
    totCar += newString.Length; 

    // if (isProblema) 
    //  _logger.Info("lsp_r2: letti: " + numCar + " caratteri"); 

} 

Mais j'ai eu problème aussi en utilisant sr.Read

Il y a quelque chose que je ne sais pas Socket Communication qui peut bloquer la Lire? Devrais-je utiliser un ReadLine parce que la ligne se termine avec CRLF? Dois-je utiliser d'autres méthodes?

Désolé pour mon anglais. Faites-moi savoir si je dois donner d'autres informations.

TIA

Alessandro

+0

Non seulement la demande/lecture peut bloquer, même WebRequest asynchrone peut échouer. La cause première peut être un réseau déconnecté et bien d'autres (vous devez analyser les traces du réseau et les journaux des événements du serveur). Je mettrais votre code dans un nouveau thread, puis j'utiliser thread.join après votre timeout pour tester si le thread est terminé. Si la demande n'a pas réussi, vous pouvez réessayer le thread. – josef

+0

Merci @josef avez-vous un exemple comment implémenter cela? De quel temps parlez-vous? –

Répondre

0

Voici un extrait de code sans contrôle sur la façon de le faire avec un fil et délai d'attente externe (deuxième fil):

using System; 
using System.Web; 
using System.Threading; 

public class myWebRequest:IDisposable{ 
    public class myEventArgs:System.EventArgs{ 
     public string msg; 
     public myEventArgs(string s){ 
      msg=s; 
     } 
    } 
    public delegate void myDelegate (myEventArgs args); 

     public myDelegate theDelegate; 

     void onUpdate (myEventArgs arg) 
     { 
      if (theDelegate != null) 
       theDelegate (arg); 
     } 

     Thread myThread = null; 
     Thread watchThread = null; 

    object lockObject = new object(); 
    bool bThreadRunning = false; 

    public myWebRequest(){ 
    } 
    public void Dispose(){ 
     if (watchThread != null) { 
      watchThread.Abort(); 
      watchThread = null; 
     } 
     if (myThread != null) { 
      myThread.Abort(); 
      myThread = null; 
     } 
    } 

    public void startRequest(){ 
     if (myThread != null) { 
      myThread.Abort(); 
      myThread = null; 
     } 
     myThread = new Thread (theThread); 
     myThread.Start(); 

     //start the watch thread 
     if (watchThread != null) { 
      watchThread.Abort(); 
      watchThread = null; 
     } 
     watchThread = new Thread (theWatchThread); 
     watchThread.Start(); 
    } 

    void theWatchThread(){ 
     try{ 
      Thread.Sleep (5000); 
      if (bThreadRunning && myThread != null) { 
       //thread is running, try a join 
       if (myThread.Join (5000)) { 
        //join did work, although thread should have finished 
        myThread.Abort(); 
        myThread = null; 
        bThreadRunning = false; 
        onUpdate(new myEventArgs("failed")); 
       } 
      } 
     }catch(ThreadAbortException ex){ 
     } 
     catch(Exception ex){ 
     } 
    } 

    void theThread(){ 
     string sMsg = ""; 
     try { 
      bThreadRunning=true; 
      //call the possibly blocking function 
      sMsg=myWebRequest.CallWebServiceProblem("url", 4000); 
      onUpdate(new myEventArgs(sMsg)); 
     }catch(ThreadAbortException ex){ 

     } 
     catch (Exception ex) { 

     } 
     bThreadRunning = false; 
    } 

    static string CallWebServiceProblem(string url, int timeout) 
    { 

     string s = ""; 

     ServicePointManager.DefaultConnectionLimit = 10; 


     _logger.Trace("web service: {0} timeout: {1}", url, timeout); 
     HttpWebRequest wrGETURL = null; 
     try 
     { 
      bool isProblema = url.IndexOf("lsp_r2") >= 0; 
      if (isProblema) 
       _logger.Info("Sono in lsp_r2..."); 

      wrGETURL = (HttpWebRequest)WebRequest.Create(url); 
      wrGETURL.Credentials = CredentialCache.DefaultCredentials; 

      wrGETURL.ReadWriteTimeout = 10000; // Per vedere se sistema un po' i timeout... 
      if (timeout != 0) 
       wrGETURL.Timeout = 3000; // timeout... 

      Stream ojstream = null; 
      StreamReader sr = null; 
      HttpWebResponse httpresponse = null; 

      try 
      { 
       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo GetResponse..."); 

       httpresponse = (HttpWebResponse)wrGETURL.GetResponse(); 

       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo GetResponseStream..."); 

       ojstream = httpresponse.GetResponseStream(); 
       Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 

       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo StreamReader..."); 

       sr = new StreamReader(ojstream, encode); 

       if (isProblema) 
        _logger.Info("lsp_r2: inizio a leggere"); 

       s = sr.ReadToEnd(); 
       if (isProblema) 
       { 
        _logger.Info("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
        System.Diagnostics.Debug.WriteLine("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
        #if DEBUG 
        // _logger.Info("lsp_r2: ho letto " + s); 
        System.Diagnostics.Debug.WriteLine("lsp_r2: ho letto " + s); 
        #endif 
       } 
      } 
      catch (Exception ex) 
      { 
       _logger.Error("web service: {0} timeout: {1} exception: {2} - {3}", url, timeout, ex.Message, ex.InnerException != null ? ex.InnerException.Message : "??"); 
       throw new Exception(ex.Message); 
      } 
      finally 
      { 

       if (isProblema) 
        _logger.Info("lsp_r2: Concludo..."); 

       if (sr != null) 
       { 
        sr.Close(); 
        sr.Dispose(); 
       } 

       if (ojstream != null) 
       { 
        ojstream.Close(); 
        ojstream.Dispose(); 
       } 

       if (httpresponse != null) 
       { 
        httpresponse.Close(); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(ex.Message); 
     } 
     finally 
     { 

     } 

     return s; 

    } 
} 

Pour l'utiliser à partir d'un formulaire:

void doTest(){ 
     myWebRequest theRequest = new myWebRequest(); 
     theRequest.theDelegate += new myWebRequest.myDelegate (onReceive); 
    } 
    void onReceive(myWebRequest.myEventArgs args){ 
     //updateGUI? 
    } 

Dans onReceive, vous obtiendrez "failed" ou le résultat.

Le code ci-dessus est seulement un squelette ...

+0

Merci @josef Je vais faire un peu de test. Il n'y a pas une méthode plus simple pour ajouter un timeout à ReadToEnd? –

+0

Le problème est que l'API est défectueuse et qu'elle n'expire pas toujours. Donc, la solution de contournement est difficile. Même avec un changement de code asynchrone, vous risquez de rencontrer de tels problèmes. – josef