SmtpClient.SendAsync - Wie die Anwendung zu beenden, bevor der Rückruf Verlassen ausgelöst wird?

StackOverflow https://stackoverflow.com/questions/1766021

  •  21-09-2019
  •  | 
  •  

Frage

Ich brauche E-Mails senden Asychronously über eine Konsolenanwendung. Ich brauche ein paar DB-Updates auf dem Rückruf zu tun, aber meine Anwendung wird beendet, bevor der Rückruf Code ausgeführt wird!

Wie kann ich das verhindern in einer netten Art und Weise, anstatt einfach Erraten , wie lange zu warten, bevor verlassen. Ich würde die Async Anrufe vorstellen, erhalten in irgendeiner Form von Fäden gelegt? Ist es möglich, zu überprüfen, ob jeder aufgerufen werden warten?

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("system@domain.com", "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
}
War es hilfreich?

Lösung

Erstellen Sie eine Manual Anruf WaitOne man es auf sie vor dem Verlassen. Wenn der letzte E-Mail / dbupdate ausgeführt wird, ruft Set auf dem Manual.


public static void Main(string[] args)
{
    object someArrows = ">>>";
    var users = Repository.GetUsers();
    SmtpClient client = new SmtpClient("Host");
    client.SendCompleted += SendCompletedCallback;
    MailAddress from = new MailAddress("system@domain.com", "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();
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top