SmtpClient.SendAsync - Как остановить завершение работы приложения до запуска обратного вызова?

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

  •  21-09-2019
  •  | 
  •  

Вопрос

Мне нужно отправлять электронные письма асинхронно через консольное приложение.Мне нужно выполнить некоторые обновления базы данных при обратном вызове, но мое приложение завершается до запуска кода обратного вызова!

Как я могу предотвратить это приятным образом, а не просто угадывание как долго ждать перед выходом.Я бы предположил, что асинхронные вызовы помещаются в какую-то форму потока?Можно ли проверить, ожидают ли какие-либо из них вызова?

Пример кода

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
}
Это было полезно?

Решение

Создайте вызов ManualResetEvent, подождите один раз на нем перед выходом.Когда выполняется последнее электронное письмо / dbupdate, вызовите Set в ManualResetEvent.


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();
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top