我有使用smtp服务器发送电子邮件的方法。使用Task.Factory
我正在调用该方法来阻止UI:
Task.Factory.StartNew(() => SendMail("mail@example.com", "Test title", "TEST body"), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(p =>
{
if (p.IsFaulted)
{
if (p.Exception != null)
{
MessageBox.Show(p.Exception.ToString());
}
return;
}
MessageBox.Show("ok");
}, TaskScheduler.FromCurrentSynchronizationContext());
现在我想修改我的代码,以便在出现问题时尝试拨打SendMail
10次。我尝试过使用do / while块,但是我无法使用它:
private void button1_Click(object sender, EventArgs e)
{
bool success = false;
int i = 0;
int max = 10;
do
{
Task.Factory.StartNew(() => SendMail("mail@example.com", "Test", "TEST1"), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(p =>
{
if (p.IsFaulted)
{
if (p.Exception != null)
{
MessageBox.Show(p.Exception.ToString());
}
return;
}
success = true;
MessageBox.Show("ok");
}, TaskScheduler.FromCurrentSynchronizationContext());
i++;
} while (!success && i < max);
if (!success)
{
MessageBox.Show("error");
}
else
{
MessageBox.Show("ok", "success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void SendMail(string address, string title, string body)
{
Thread.Sleep(10000);
MailClient.Instance.Send(address, title, body);
}
我想做的就是能够在任务中调用Specific方法,如果我得到异常,那么我想一次又一次地调用它,10次,如果经过那10次就不会成功我想表现出异常。
答案 0 :(得分:4)
这有点偏离主题,但每当我看到有人使用线程进行IO绑定操作时,我就会感到寒意:)
由于发送邮件是一种网络绑定操作,因此您可以使用.NET 4.5中添加的等待SmtpClient.SendMailAsync
。
如果我可以采取JoelC发布的实现并重构一下:
private int _maxAttempts = 10;
private async Task TrySendMailAsync(int attemptNumber)
{
var smtpClient = new SmtpClient();
var mailMsg = new MailMessage("from@test.com", "to@test.com", "Test Subject", "Test Body");
while (!success && attempts <= maxAttempts)
{
try
{
await smtpClient.SendMailAsync(mailMsg)).ConfigureAwait(false);
success = true;
}
catch
{
if (attempts >= maxAttempts)
{
throw;
}
}
attempts++;
}
}
这将允许您按照请求循环,但让作为异步IO的主作业无需执行线程池线程的unnessaceace。
答案 1 :(得分:1)
这样的事情可能会解决问题:
private int _maxAttempts = 10;
private void TrySendMail(int attemptNumber)
Task.Factory.StartNew(() => SendMail("mail@example.com", "Test title", "TEST body"), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(p =>
{
attemptNumber++;
if (p.IsFaulted)
{
if (p.Exception != null)
{
if (_attempts < _maxAttempts)
{
// Try again
TrySendMail(attemptNumber);
}
else
{
MessageBox.Show(p.Exception.ToString());
}
}
return;
}
success = true;
MessageBox.Show("ok");
}, TaskScheduler.FromCurrentSynchronizationContext());
}
它不是最漂亮的,你想看到你不会递归地多次调用它并获得堆栈溢出!十次应该没问题。
编辑: 我将尝试次数更改为一个参数,以便更安全地使用线程,以防您在线程上多次调用此发送邮件。
EDIT2:
上面提到的方法@mazharenko的实现可能如下所示:
private void TryAndRepeat(Action routine, int maxAttempts)
{
int attempts = 1 ;
bool success = false;
while (!success && attempts <= maxAttempts)
{
try
{
routine.Invoke();
success = true;
}
catch
{
if (attempts >= maxAttempts)
{
throw;
}
}
attempts++;
}
}