2017-02-28 43 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! –