2012-03-06 2 views
1

私には2つの問題があります。 1つは、送信する数百があるときに1つの行を引っ張ってmsファックスに送信することだけです。もう1つは、それが最初にそれ以降に引っ張られず、エラーを投げるということです。私は私の連絡を締めていると思った。私は問題が何であるか理解していない。コードとエラーが含まれています。リーダーはwhileループで1行を引きます。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

両方が同じデータベースに接続するため、2つの接続は必要ありません。 – jrummell

+0

2つの別々の接続を使用している理由は何ですか?あなたは本当に1つだけ必要です。また、接続を開いた後にコードが爆発しても、すぐに終了することはありません。作業コードを '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

idisposableに "using"を使用している場合は、最後の括弧の後にかっこを終わらせるのですか?あるいは、mysqlコマンドを "using"セクションに置くだけですか?使用セクションは全領域をカバーするのでしょうか、それともトップセクションの小さなセクションですか? –

+0

@ RV-10Builder:上記のコメント中の 'using'はその使用例です。 'catch'の後に' using'ソートを開始し、 'Dispose()'メソッドが接続をクリーンアップするので 'finally'は必要ありません。 –

0

タイマーは定期的に起動し、以前のイベントが完了したかどうかは気にしません。

Background Workerを使用してファックスを送信し、キューをループしてからキューが空のときに一時停止します。

+1

...Tickを実行している間はタイマーを無効にすることができます。 –

+0

@AustinSalonen:それに問題はありますか?私はそれをしていましたが、反復回数をランダムにした後、timer_tickイベントはタイマーを起動した後も起動しなくなりました。しかし、私は決して問題を追跡するのには心配しませんでした。 –

+0

私が持っていると言うことはできません... –

0

接続オブジェクトに問題があります。いくつかの接続オブジェクトを定義しました。あなたは1つだけ必要です。ここで

は、問題の2つです:

MySqlConnection connupdate = new MySqlConnection(connString);

MySqlConnection conn = new MySqlConnection(connString);

それらの1への接続を排除します。

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へのコマンドプロンプト= conn.CreateCommand();同じ接続を使用するために??そして、MySqlConnectionを削除します。connupdate = new MySqlConnection(connString); –

+0

1つの接続オブジェクトを管理するだけで済みます。 1つのデータベース接続を管理する2つのオブジェクトを定義しました。これは、2つのオブジェクトを必要としないことです。私の編集を参照してください。 – JonH

+0

リーダーは処理を終了する前に更新を行っているので、2つの接続が必要ですが、リーダーが閉じられるまで接続を使用することはできません。 SqlDataReaderページの[備考セクション](http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx#remarksToggle)を参照してください。 –

関連する問題