仅仅因为某件事有效并不意味着它是正确的。所以我想要一些关于以下代码的反馈。
一段历史;当一个用户在我们的网站上注册时,我试图发送/排队电子邮件,但遇到线程被阻塞的问题,这是完全有意义的,因为控制器和相关的操作方法在默认情况下是同步的,而不是异步的。为了解决这个问题,我把以下内容放在一起,但不确定这是不是最好的方法。
[HttpPost, AllowAnonymous]
public async Task<ActionResult> RegisterAsync(UserRegisterUserViewModel userRegisterUserViewModel)
{
if (ModelState.IsValid)
{
var user = new UserDto
{
UserName = userRegisterUserViewModel.UserName,
Password = userRegisterUserViewModel.Password,
AuthType = userRegisterUserViewModel.AuthType,
Active = 0
};
Guid userId = _userService.AddUser(user);
if (userId != Guid.Empty)
{
// Send Registration E-mail
await Task.Run(() => _userMailer.RegistrationConfirmation(user).SendAsync(),
new CancellationToken(false));
// Display Confirm View
return PartialView("_RegistrationConfirmation");
}
ModelState.AddModelError("UserName", "Unable to create account");
}
return PartialView("_Registration");
}发布于 2013-01-02 22:16:13
我不确定ASP.NET线程被阻塞会导致什么样的“问题”,但是关于您的async/await代码:
在new CancellationToken(false)中没有意义,这和CancellationToken.None是一样的,这就像不提供parameter.
cancellationToken可能没有指向Task.Run一样,它在线程池线程上执行SendAsync。如果SendAsync是一个合适的async方法,那么它可以直接被await。例如,该行代码可以替换为:
await _userMailer.RegistrationConfirmation(user).SendAsync();编辑:
由于SendAsync在SmtpClient上,您应该使用wrap this API (使用Event-based Asynchronous Pattern)进入await-friendly应用程序接口(使用Task-based Asynchronous Pattern):
public static Task SendTaskAsync(this SmtpClient client, MailMessage message)
{
var tcs = new TaskCompletionSource<object>();
SendCompletedEventHandler handler = null;
handler = (s,e) =>
{
client.SendCompleted -= handler;
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(null);
};
client.SendCompleted += handler;
client.SendAsync(message, null);
return tcs.Task;
}然后您可以对SmtpClient.SendTaskAsync的结果执行await操作。
您不想使用Task.Run,因为这会导致您使用return early from ASP.NET requests, which is a dangerous practice (正如我在我的博客中所解释的那样)。
https://stackoverflow.com/questions/14117633
复制相似问题