1

仅仅因为某事有效并不意味着它是正确的。所以我想对以下代码进行一些反馈。

一点历史;当用户在我们的网站上注册并遇到线程被阻止的问题时,我试图发送/排队电子邮件,考虑到默认情况下控制器和相关操作方法是同步而不是异步的事实,这完全有意义。为了解决这个问题,我将以下内容放在一起,但不确定这是否是最好的方法。

 [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");
    }
4

1 回答 1

2

我不确定 ASP.NET 线程被阻止会导致什么样的“问题”,但关于您的async/await代码:

  • 中没有意义new CancellationToken(false),这与 相同CancellationToken.None,这与不提供cancellationToken参数相同。
  • 可能没有意义Task.Run,它SendAsync在线程池线程上执行。如果SendAsync是正确的async方法,则可以await直接编辑。

例如,该行代码可以替换为:

await _userMailer.RegistrationConfirmation(user).SendAsync();

编辑:

由于SendAsync是 on SmtpClient,您应该将此 API (使用基于事件的异步模式)包装成一个友好的 API(使用基于任务的异步模式):await

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;
}

然后你可以await得到SmtpClient.SendTaskAsync.

您不想使用Task.Run,因为这会导致您从 ASP.NET 请求中提前返回,这是一种危险的做法(正如我在博客中解释的那样)。

于 2013-01-02T14:16:13.210 回答