2012-03-06 18 views
1

我有兩個問題。一個是,當有幾百個要發送的時候,它只拉一行併發送給ms傳真。另一個是它在第一次之後不再拉動,並且拋出錯誤。我以爲我正在關閉我的聯繫。我不明白問題是什麼。我已經包含了代碼和錯誤。閱讀器只在while循環中拉一行C#

Service1.cs

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.Timers; 
using MySql.Data.MySqlClient; 
using FAXCOMLib; 
using FAXCOMEXLib; 

namespace ProcessFaxes 
{ 
public partial class Service1 : ServiceBase 
{ 
    public Service1() 
    { 
     InitializeComponent(); 
    } 
    public static Timer timer = new Timer(); 

    protected override void OnStart(string[] args) 
    { 

     timer.Elapsed += new ElapsedEventHandler(Tick); 
     timer.Interval = 600000; // every 10 minutes 
     timer.Enabled = true; 
     // Console.ReadLine(); 
    } 

    protected override void OnStop() 
    { 

    } 

    public static void Tick(object source, ElapsedEventArgs e) 
    { 
     string connString = "Server=localhost;Port=3306;Database=communications;Uid=root;password=pass;"; 
     MySqlConnection conn = new MySqlConnection(connString); 
     MySqlCommand command = conn.CreateCommand(); 

     MySqlConnection connupdate = new MySqlConnection(connString); 
     MySqlCommand commandupdate = connupdate.CreateCommand(); 

     command.CommandText = "SELECT * FROM outbox WHERE `faxstat` = 'Y' AND `fax` <> '' AND `faxpro` = 'PENDING'"; 
     //command.CommandText = "UPDATE blah blah"; 
     //conn.Open(); 
     //conn.ExecuteNonQuery(); 
     //conn.Close(); 

     try 
     { 

      conn.Open(); 
      connupdate.Open(); 

     } 
     catch (Exception ex) 
     { 
      // Console.WriteLine(Ex.Message); 
       LogException(ex.ToString()); 

     throw; // or whatever you want to do with it 
     } 
     MySqlDataReader reader = command.ExecuteReader(); 

     if (reader.HasRows) 
     { 

      while (reader.Read()) 
      { 
       //Console.WriteLine(reader["filepath"].ToString()); 
       SendFax(reader["id"].ToString(), reader["filepath"].ToString(), @"C:\FAXDOC\" + reader["filepath"].ToString(), reader["account"].ToString(), reader["fax"].ToString(), reader["fax_orig"].ToString()); 
       string id = reader["id"].ToString(); 
       commandupdate.CommandText = "UPDATE outbox SET `faxpro` = 'DONE' WHERE `id` = '" + id + "'"; 
       commandupdate.ExecuteNonQuery(); 

      } 
     } 

     conn.Close(); 
     connupdate.Close(); 
    } 

    public static void SendFax(string DocumentId, string DocumentName, string FileName, string RecipientName, string FaxNumber, string RecipientHomePhone2) 
    { 
     if (FaxNumber != "") 
     { 
      try 
      { 
       FAXCOMLib.FaxServer faxServer = new FAXCOMLib.FaxServerClass(); 
       faxServer.Connect(Environment.MachineName); 


       FAXCOMLib.FaxDoc faxDoc = (FAXCOMLib.FaxDoc)faxServer.CreateDocument(FileName); 

       faxDoc.RecipientName = RecipientName; 
       faxDoc.FaxNumber = FaxNumber; 
       faxDoc.BillingCode = DocumentId; 
       faxDoc.DisplayName = DocumentName; 
       faxDoc.RecipientHomePhone = RecipientHomePhone2; 

       int Response = faxDoc.Send(); 


       faxServer.Disconnect(); 

      } 
      catch (Exception Ex) { 

       // Console.WriteLine(Ex.Message); 
       LogException(Ex.ToString()); 

     throw; // or whatever you want to do with it 
      } 
     } 



    } 

    public static void LogException(string ErrorDescription) 

    { 

     // The name of our log in the event logs 

     string Log = "Process Faxes"; 



     // Check to see fi the log for AspNetError exists on the machine 

     //   If not, create it 

     if ((!(EventLog.SourceExists(Log)))) 

     { 


EventLog.CreateEventSource(Log, Log); 

     } 



     // Now insert your exception information into the AspNetError event log 

     EventLog logEntry = new EventLog(); 

     logEntry.Source = Log; 

     logEntry.WriteEntry(ErrorDescription, EventLogEntryType.Error); 

     } 


    } 
} 

錯誤

Event Type: Error 
Event Source: Process Faxes 
Event Category: None 
Event ID: 0 
Date:  3/6/2012 
Time:  2:01:06 PM 
User:  N/A 
Computer: FAXSERVER 
Description: 
MySql.Data.MySqlClient.MySqlException (0x80004005): Too many connections 
    at MySql.Data.MySqlClient.MySqlStream.ReadPacket() 
    at MySql.Data.MySqlClient.NativeDriver.Open() 
    at MySql.Data.MySqlClient.Driver.Open() 
    at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings) 
    at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection() 
    at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver() 
    at MySql.Data.MySqlClient.MySqlPool.GetConnection() 
    at MySql.Data.MySqlClient.MySqlConnection.Open() 
    at ProcessFaxes.Service1.Tick(Object source, ElapsedEventArgs e) in C:\Documents and Settings\bruser\My Documents\Visual Studio 2010\Projects\ProcessFaxes\ProcessFaxes\Service1.cs:line 56 
+9

**警告**您的代碼容易受到sql注入攻擊! –

+0

因爲它們都連接到同一個數據庫,所以不需要兩個連接。 – jrummell

+0

你使用兩個單獨的連接的任何原因?你真的只需要一個。另外,如果您的代碼在您打開連接後爆炸,它們將不會立即關閉。你應該將你的工作代碼移動到你的'try'中,然後用'finally'關閉連接。請參閱下面的答案。 –

回答

2

我想你應該重構了一下。我解釋一點在評論之上,但在這裏就是我要改變它(我加了一些評論對你來說太):

public static void Tick(object source, ElapsedEventArgs e) 
{ 
    // Prevent another Tick from happening if this takes longer than 10 minutes 
    (source as Timer).Enabled = false; 

    // It would be better practice to put this in a settings or config file 
    // so you can change it without having to recompile your application 
    string connString = "Server=localhost;Port=3306;Database=communications;Uid=root;password=pass;"; 

    // I won't change them here, but since these classes implement IDisposable, 
    // you should be using a using statement around them: 
    // using (var conn = new MySqlConnection(connString)) 
    // { 
    //  // use conn 
    // } 
    MySqlConnection conn = new MySqlConnection(connString); 
    MySqlCommand command = conn.CreateCommand(); 
    MySqlCommand updateCommand = conn.CreateCommand(); 

    command.CommandText = "SELECT * FROM outbox WHERE `faxstat` = 'Y' AND `fax` <> '' AND `faxpro` = 'PENDING'"; 

    try 
    { 
     conn.Open(); 

     MySqlDataReader reader = command.ExecuteReader(); 

     if (reader.HasRows) 
     { 
      while (reader.Read()) 
      { 
       SendFax(reader["id"].ToString(), reader["filepath"].ToString(), @"C:\FAXDOC\" + reader["filepath"].ToString(), reader["account"].ToString(), reader["fax"].ToString(), reader["fax_orig"].ToString()); 
       string id = reader["id"].ToString(); 
       // I would use a prepared statement with either this query 
       // or a stored procedure with parameters instead of manually 
       // building this string (more good practice than worrying about 
       // SQL injection as it's an internal app 
       updateCommand.CommandText = "UPDATE outbox SET `faxpro` = 'DONE' WHERE `id` = '" + id + "'"; 
       updateCommand.ExecuteNonQuery(); 

      } 
     } 
    } 
    catch (Exception ex) 
    { 
     LogException(ex.ToString()); 
     throw; 
    } 
    finally 
    { 
     // If you're not going to use using-statements, you might want to explicitly 
     // call dispose on your disposable objects: 
     // command.Dispose(); 
     // updateCommand.Dispose(); 
     conn.Close(); 
     // conn.Dispose(); 
    } 

    // Enable the timer again 
    (source as Timer).Enabled = true; 
} 

至於爲什麼你只收到一排,當你期待很多,我懷疑你的SQL有問題。

+3

我會將這些語句封裝在'using'塊中,這將有助於管理資源。 – JonH

+0

如果我將「using」用於idisposable ..是否在最後括號之後結束括號還是僅將mysql命令放在上面現在註釋掉的「using」部分中?使用部分覆蓋整個區域還是隻是頂部的小部分? –

+0

@ RV-10Builder:上面評論中的「使用」只是其用法的一個例子。我會開始''使用'它在哪裏,並在'catch'結束後 - 你不需要'finally',因爲'Dispose()'方法會爲你清理連接。 –

0

你不應該使用一個計時器。

計時器會定期觸發,並且不關心前一個事件是否已完成。

看看如何使用Background Worker來發送您的傳真,讓它在隊列中循環,然後在隊列爲空時暫停。

+1

...或者可以在執行「滴答」時禁用定時器。 –

+0

@AustinSalonen:你有什麼問題嗎?我曾經那樣做,但是在隨機數次的迭代之後,timer_tick事件在啓動計時器後不會再觸發。不過,我從來沒有打算過這個問題。 –

+0

不能說我有... –

0

問題在於你的連接對象。你已經定義了幾個連接對象。你只需要一個。

這裏有兩個問題:

MySqlConnection connupdate = new MySqlConnection(connString);

MySqlConnection conn = new MySqlConnection(connString);

消除對他們的一個連接。

這裏是修復你的代碼的一種方法:

string connString = "Server=localhost;Port=3306;Database=communications;Uid=root;password=pass;"; 

using(MySqlConnection conn = new MySQLConnection(connString)) 
    { 
    using(MySQlCommand command = conn.CreateCommand()) 
    { 
     command.CommandText = "SELECT ..."; 
     conn.Open(); 
     using(MySqlDataReader reader = command.ExecuteReader()) 
      { 
      //process rows... 
      } 
    } 
    } 
+0

因此,更改MySqlCommand commandupdate = connupdate.CreateCommand();到MySqlCommand commandupdate = conn.CreateCommand();爲了使用相同的連接?並取消MySqlConnection connupdate = new MySqlConnection(connString); –

+0

你只需要管理一個連接對象。你已經定義了兩個對象來管理一個數據庫連接 - 關鍵是你不需要兩個對象。看我的編輯。 – JonH

+0

在閱讀器完成處理之前,他仍然需要兩個連接,因此在閱讀器關閉之前,您無法使用連接。請參閱SqlDataReader頁面的[註釋部分](http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader.aspx#remarksToggle) –