2017-08-29 90 views
-7

請隨意創建一個Windows窗體應用程序。重現錯誤禁用網絡連接並運行代碼。它會在每1秒後嘗試重新連接。在4-5次嘗試啓用網絡連接並進入調試模式後,您會注意到即使提取產品,Reconnect()方法也被調用4-5次。一旦產品被提取,爲什麼它會一次又一次地調用Reconnect()方法?Winform遞歸循環 - 一次又一次調用方法

 string apiUrl = "https://api.gdax.com/products"; 
     string json; 

     private void Form1_Load(object sender, EventArgs e) 
     {    
      try 
      {     
       if (FillProducts()) // product need first 
       { 
       } 
      } 
      catch (WebException ex) 
      { 
       ReconnectOnError(ex); 
      } 
     } 
     private bool FillProducts() 
     { 
      bool isDone = false; 
      try 
      { 
       json = GetGDXJSONData(apiUrl); 
       JsonSerializer serializer = new JsonSerializer(); 
       DataTable dt = (System.Data.DataTable)Newtonsoft.Json.JsonConvert.DeserializeObject(json, (typeof(System.Data.DataTable))); 

       count = dt.Rows.Count; 

       if (count > 0) 
        isDone = true; 
      } 
      catch (Exception ex) 
      {    
       isDone = false; 
       ReconnectOnError(ex); 
      } 
      return isDone; 
     } 

     int count = 0; 
     private void ReconnectOnError(Exception errorMessage) 
     { 
      try 
      { 
       Thread.Sleep(1000); 
       if (count < 1) 
       { 
        FillProducts();  // it comes on this point again and again even the count is greater than 1 
        Reconnect(); 
       } 
       else 
       { 
        Reconnect(); 
       } 
      } 
      catch (WebException ex) 
      { 
       ReconnectOnError(ex); 
      } 
     } 

     private void Reconnect() 
     { 
      // why this is called the number of times the attempt was made to fill the products? 
     }  

     private string GetGDXJSONData(string apiUrl) 
     { 
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl); 

      request.Method = "GET"; 
      request.ContentType = "application/json"; 
      request.UserAgent = "gdax-node-client"; 
      request.Accept = "application/json"; 

      HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
      string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd(); 

      return responseString; 
     } 
    } 

編輯 - 這是一個示例代碼和我做很多的重新連接()方法的事情,一旦產品有牽強。 另外,如果錯誤發生在產品被提取後,則不要獲得產品,只需調用Reconnect()方法,這就是其他原因。

編輯2 - 請不要僅僅通過查看代碼來回復。如果您創建了一個表單並自己運行,並且可以自己查看錯誤,請告知如何解決此問題。

更新 - 我知道我進入了無限次迭代。我想這和現在的作品:

string apiUrl = "https://api.gdax.com/products"; 
    string json; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     if (FillProducts()) // product need first 
     { 
     } 
    } 

    bool isOk = false; 
    private string GetGDAXProducts() 
    { 
     try 
     { 
      json = GetGDXJSONData(apiUrl); 
      return json; 
     } 
     catch (Exception ex) 
     {    
      return "-1"; 
     } 
    } 

    int count = 0; 
    private bool FillProducts() 
    { 
     bool isDone = false; 
     string retVal = GetGDAXProducts(); 

     while (retVal == "-1") 
     { 
      retVal = GetGDAXProducts(); 
     } 

     if (retVal != "-1") 
     { 
      JsonSerializer serializer = new JsonSerializer(); 
      DataTable dt = (System.Data.DataTable)Newtonsoft.Json.JsonConvert.DeserializeObject(json, (typeof(System.Data.DataTable))); 

      count = dt.Rows.Count; 

      if (count > 0) 
       isDone = true; 
     } 

     return isDone; 
    } 

    private string GetGDXJSONData(string apiUrl) 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl); 

     request.Method = "GET"; 
     request.ContentType = "application/json"; 
     request.UserAgent = "gdax-node-client"; 
     request.Accept = "application/json"; 

     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
     string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd(); 

     return responseString; 
    } 
+2

其歸因於其他部分'如果(計數<0)' –

+0

再次fillproducts後調用它... – Proxytype

+0

我不得不這樣做。它不是在該行未來雖然。如果你運行代碼,你會看到它調用FillProducts();重新連接();一次又一次,即當沒有互聯網時第一次嘗試重新連接的次數 – user1254053

回答

1

這是因爲如果沒有網絡連接,然後調用API的URL連接失敗,並在您catch塊,您正在嘗試重新連接

 catch (Exception ex) 
     {    
      isDone = false; 
      ReconnectOnError(ex); 
     } 
+0

是的我試圖重新連接,但是我的問題是一旦互聯網恢復,爲什麼它仍然會調用4-5倍的Reconnect()方法? – user1254053

0

enter image description here

當沒有互聯網connection.Count變量總是零。

+0

請點擊「在這裏輸入圖片描述」鏈接 –

1

你有一個無意的循環在這裏:

如果FillProducts失敗,它會調用自身...

  1. 迭代:FP失敗
  2. 迭代:FP調用ReconnectOnEx調用FP,這再次失敗
  3. 迭代:FP調用ReconnectOnEx調用FP調用ReconnectOnEx ...

n。迭代:....調用成功的FP 並返回

現在整個堆棧將展開,每次迭代調用Reconnect

private bool FillProducts() 
    { 
     bool isDone = false; 
     try 
     { 
      /* ... Fails if no connection ... */ 
     } 
     catch (Exception ex) 
     {    
      isDone = false; 
      ReconnectOnError(ex); // ==> BLOCKS !! 
     } 
     return isDone; 
    } 

    int count = 0; 
    private void ReconnectOnError(Exception errorMessage) 
    { 
     try 
     { 
      Thread.Sleep(1000); 
      if (count < 1) 
      { 
       FillProducts();  // <== Will result in another call to this method. Returns on 1st Succeeding call to FillProducts. 
       Reconnect();  // <== Will be called as soon as FillProducts returns. 
      } 
      else 
      { 
       Reconnect(); 
      } 
     } 
     catch (WebException ex) 
     { 
      ReconnectOnError(ex); 
     } 
    } 

爲了避免這種情況,你可以移動的 「重試」 的邏輯到FillProducts方法:

private bool FillProducts() 
    { 
     // To prevent waiting forever ... 
     int retryCount = 10; 

     bool isDone = false; 
     while (!isDone && (retryCount-- > 0)) 
     { 
      try 
      { 
       /* ... Fails if no connection ... */ 

       // OnSuccess=> 
       isDone = true; // will break the loop. 
      } 
      catch (Exception ex) // You should actually catch a more specific Exception here 
           // ... but that's a different question. 
      {    
       isDone = false; 
       // Just omit this! >>> ReconnectOnError(ex); // ==> BLOCKS !! 
       // If you want, you can add a little delay here ... 
       Thread.Sleep(1000); 
       // From your code, I guess this has to be called on failure ... 
       Reconnect(); 
      } 
     } 
     return isDone; 
    } 

其他一些點來考慮:

  1. 你不應該在GUI線程上做網絡I/O。您的GUI可能無法響應。考慮使用異步/等待(任務異步模式)

  2. 捕捉Exception可能不是最好的主意。你應該捕捉最具體的異常,並讓其餘的通過調用者處理。