2017-02-28 46 views
1

我正在使用一個Windows服務的調用API,得到響應和更新Sql表它工作正常,但有一段時間它是Hit API兩次。我無法理解。這裏是我的代碼Windows服務Hit API多次有時

protected override void OnStart(string[] args) 
{ 
    this.timer = new System.Timers.Timer(15000D); 
    this.timer.AutoReset = true; 
    this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed); 
    this.timer.Start(); 
} 
protected override void OnStop() 
    { 
    this.timer.Stop(); 
    this.timer = null; 
} 
protected void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    this.proccessQue(); 
} 

,這裏是proccessQue()方法

//SELECT record form table 
SqlDataAdapter adap = new SqlDataAdapter("SELECT * FROM TABLE_NAME WHERE is_done=0 AND date>DATEADD(minute,-5,GETDATE())", conn); 
DataTable dt = new DataTable(); 
adap.Fill(dt); 
for (int i = 0; i < dt.Rows.Count; i++) 
{ 
    string parameters= dt.Rows[i]["parameters"] + ""; 
    string api = "http://domain.com/page.aspx?parameters=" + parameters; 
    HttpWebRequest httpreq = (HttpWebRequest)WebRequest.Create(api); 
    HttpWebResponse httpres = (HttpWebResponse)httpreq.GetResponse(); 
    StreamReader sr = new StreamReader(httpres.GetResponseStream()); 
    string results = sr.ReadToEnd(); 
    sr.Close(); 
    if (results.Contains("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")) 
    { 
    try 
    { 
     string response= ""; 
     XmlDocument xmlDoc = new XmlDocument(); 
     xmlDoc.LoadXml(results); 
     var res2 = xmlDoc.SelectNodes("RechargeRequest/RequestResponse/APIRef"); 
     if (res2 != null) 
     response= res2[0].InnerText; 
     SqlCommand cmd = new SqlCommand("UPDATE TABLE_NAME SET field='" + response+ "',is_done=1 WHERE id=" + rId, conn); 
     conn.Open(); 
     cmd.ExecuteNonQuery(); 
     conn.Close(); 
    } 
    catch (Exception ex) 
    { 

    } 
    } 
} 

請幫我在哪裏,我錯了。

+0

多種事情1.您的API調用處於記錄循環中。所以會根據你的循環結果命中0-n次。這可能是您的查詢返回多個方法。 2.是否有可能你的processQueue方法比定時器的每一個已經發生的事件花費更長的時間?我的建議是1。檢查查詢的結果,因爲它可能會返回多於一條記錄2.停止計時器在已過的事件中處理隊列,然後重新啓動它。最後,鑑於這是2017年,您最好使用異步/等待模式,並使用更強大的HttpClient類來處理Web請求。 – Nico

+0

哦,最後你有很多IDisposable的不配置 – Nico

+0

是的,它可能是查詢返回多於1行。如何在經過的事件中停止計時器處理隊列,然後重新啓動它?請幫幫我。我正在使用此服務進行充值網站,因此無法延長充電時間後計時器的使用時間。 –

回答

1

基於我對原始問題的評論,有幾件事要看。

  1. API將根據查詢結果命中0到n次。現在,定時器將爲每個間隔異步執行timer_Elapsed()方法。因此,如果processQue()方法花費的時間超過15秒,則可能會爲每個項目調用API多次。

因此一個選擇是StopprocessQue()方法結束定時器執行的處理邏輯和Start()計時器。如:

protected void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    this.timer.Stop(); //stop the timer 
    this.proccessQue(); //process the queue 
    this.timer.Start(); //restart the timer 
} 

因此,這保證了processQue();完成之前再次調用了timer_Elapsed()事件。

現在在processQue()方法中發生異常時,執行將不會繼續。它取決於你如何處理這個,但一個簡單的try .. catch將處理例外(不正確,但會)。

現在我對代碼的第二個關注,這與多次執行的原因無關,是使用類而不是正確地處理事情。

首先.. Why use a SqlDataAdapter when a SqlDataReader will produce a faster execution.這是基於意見,但不需要DataTable,並將整個結果讀入內存。 ho看起來您只使用了兩列(不確定其中的rId來自哪裏),因此不要使用*,而是定義實際需要的列名稱。這將減少從Sql查詢中查詢和流式傳輸的數據量。在小型查詢中可能看起來微不足道,但對於更大的查詢和更大的數據集可能會產生重大影響。

我看到的下一個問題是使用IDisposable而不處置它們。

  1. SqlDataAdapter
  2. StreamReader
  3. SqlCommand

這些是從IDisposable繼承所以應包裹在using語句或設置的手動調用Dispose()方法的所有類。

+0

Thankyou @Nico! –