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場合は、直接編集できます。SendAsyncasyncawait

たとえば、そのコード行は次のように置き換えることができます。

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

編集:

SendAsyncがオンになっているため、この API (イベント ベースの非同期パターンを使用) を使いやすい API (タスク ベースの非同期パターンを使用) にラップSmtpClientする必要があります。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

ASP.NET 要求から早期Task.Runに返されるため、使用したくありません。これは危険な行為です(ブログで説明しています)。

于 2013-01-02T14:16:13.210 に答える