SmtpClient.SendAsync - 如何在触发回调之前停止应用程序退出?
-
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,在退出之前调用WaitOne 就可以了。当执行最后一次电子邮件/数据库更新时,调用 ManualResetEvent 上的 Set。
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();
}
}
不隶属于 StackOverflow