2009-11-19 3 views
8

Ich muss E-Mails asynchron über eine Konsolenanwendung senden. Ich muss einige DB-Updates auf dem Rückruf durchführen, aber meine Anwendung wird beendet, bevor der Rückrufcode ausgeführt wird!SmtpClient.SendAsync - Wie kann die Anwendung beendet werden, bevor der Rückruf ausgelöst wird?

Wie kann ich dies auf eine nette Art und Weise stoppen statt einfach raten wie lange warten, bevor zu beenden. Ich könnte mir vorstellen, dass die Async-Aufrufe in irgendeiner Form von Thread platziert werden? Ist es möglich zu überprüfen, ob irgendwelche Anrufe anstehen?

Beispielcode

private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) 
{ 
    // Get the unique identifier for this asynchronous operation. 
    String token = (string) e.UserState; 
    if (e.Cancelled) 
    { 
     Console.WriteLine("[{0}] Send canceled.", token); 
    } 
    if (e.Error != null) 
    { 
     Console.WriteLine("[{0}] {1}", token, e.Error.ToString()); 
    } 
    else 
    { 
     // update DB 
     Console.WriteLine("Message sent."); 
    } 
} 

public static void Main(string[] args) 
{ 
    var users = Repository.GetUsers(); 
    SmtpClient client = new SmtpClient("Host"); 
    client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback); 
    MailAddress from = new MailAddress("[email protected]", "System", Encoding.UTF8); 
    foreach (var user in users) 
    { 
     MailAddress to = new MailAddress(user.Email); 
     MailMessage message = new MailMessage(from, to); 
     message.Body = "This is a test"; 
     message.BodyEncoding = System.Text.Encoding.UTF8; 
     message.Subject = "test message 1" + someArrows; 
     message.SubjectEncoding = System.Text.Encoding.UTF8; 
     string userState = String.Format("Message for user id {0}", user.ID); 
     client.SendAsync(message, userState); 
     message.Dispose(); 
    } 

    // need to wait here until I have received a callback for each message 
    // otherwise the application will exit 
} 

Antwort

8

ein WaitOne Manual Anruf Erstellen einer auf sie vor dem Verlassen. Wenn die letzte E-Mail/dbupdate ausgeführt wurde, rufen Sie Set auf ManualResetEvent auf.


public static void Main(string[] args) 
{ 
    object someArrows = ">>>"; 
    var users = Repository.GetUsers(); 
    SmtpClient client = new SmtpClient("Host"); 
    client.SendCompleted += SendCompletedCallback; 
    MailAddress from = new MailAddress("[email protected]", "System", Encoding.UTF8); 
    int numRemaining = users.Length; 
    using(ManualResetEvent waitHandle = new ManualResetEvent(numRemaining == 0)) 
    { 
     object numRemainingLock = new object(); 
     foreach(var user in users) 
     { 
      MailAddress to = new MailAddress(user.Email); 
      MailMessage message = new MailMessage(from, to); 
      try 
      { 
       message.Body = "This is a test"; 
       message.BodyEncoding = System.Text.Encoding.UTF8; 
       message.Subject = "test message 1" + someArrows; 
       message.SubjectEncoding = System.Text.Encoding.UTF8; 
       string userState = String.Format("Message for user id {0}", user.ID); 
       client.SendCompleted += delegate 
       { 
        lock(numRemainingLock) 
        { 
         if(--numRemaining == 0) 
         { 
          waitHandle.Set(); 
         } 
        } 
       }; 
       client.SendAsync(message, userState); 
      } 
      catch 
      { 
       message.Dispose(); 
       throw; 
      } 
     } 
     waitHandle.WaitOne(); 
    } 
} 
+0

Hallo, könnten Sie ein Beispiel dafür geben, wie Sie dies empfehlen würden? Ich habe meine Antwort aktualisiert, um Ihnen ein Beispiel zu zeigen – James

+0

Sie setzen SendCompleted + = SendCompletedCallback, aber dann in der Schleife, die Sie einem Delegierten SendCompleted zuweisen? Bedeutet dies, dass der Delegate-Code ausgeführt wird und dann der SendCompletedCallback aufgerufen wird? – James

+0

Ja. Beachten Sie jedoch, dass die Reihenfolge, in der die Callbacks aufgerufen werden, nicht garantiert ist. Also kann der SendCompleted entweder SendCompletedCallback 1st oder mein Delegierter 1st anrufen. –

Verwandte Themen