PasswordSignInAsync在.Core App中挂起

Dan*_*ary 9 .net f# asp.net-identity asp.net-core

我正在用F#构建一个.NET核心Web应用程序,我正在尝试设置Identity.我有一个基本版本的Register方法,它在数据库中创建一个用户并创建cookie:

[<HttpPost>]
[<AllowAnonymous>]
member this.Register([<FromBody>]model: RegisterViewModel) =
    if not (isNull model.Email) && model.Password = model.ConfirmPassword then
        let user = ApplicationUser(userName = model.Email, email = model.Email, password = model.Password)
        let result = userManager.CreateAsync(user, model.Password) |> Async.AwaitTask |> Async.RunSynchronously
        if result.Succeeded then
            signInManager.SignInAsync(user, isPersistent = false) |> Async.AwaitTask |> Async.RunSynchronously
            true
        else
           false 
    else
        false
Run Code Online (Sandbox Code Playgroud)

但是,我的Login实现挂起:

[<HttpPost>]
[<AllowAnonymous>]
member this.Login([<FromBody>]model: LoginViewModel) =
    if not (isNull model.Email && isNull model.Password) then
        let result = signInManager.PasswordSignInAsync(model.Email, model.Password, false, lockoutOnFailure = false) |> Async.AwaitTask |> Async.RunSynchronously
        if result.Succeeded then true else false
    else
        false
Run Code Online (Sandbox Code Playgroud)

这是应用程序挂起的地方:

info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1]
  Executed DbCommand (5ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30']
  SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[Email], [u].[EmailConfirmed], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName]
  FROM [AspNetUsers] AS [u]
  WHERE [u].[NormalizedUserName] = @__normalizedUserName_0
Run Code Online (Sandbox Code Playgroud)

知道问题可能是什么?

sdg*_*sdh 1

根据这篇文章,处理程序可以是async(在 C# 意义上),因此将路由处理程序重写为非阻塞是有意义的,从而消除Async.RunSynchronously可能导致问题的问题。

我们可以在 F# 工作流程中编写实际逻辑async,因为这更加自动化,然后将其转换为 aTask<_>以匹配预期的 C# 签名。

[<HttpPost>]
[<AllowAnonymous>]
member this.Login([<FromBody>]model: LoginViewModel) =
  async {
    if not (isNull model.Email && isNull model.Password) 
    then
      let! result = 
        signInManager.PasswordSignInAsync(model.Email, model.Password, false, lockoutOnFailure = false) 
        |> Async.AwaitTask 

      return result.Succeeded
    else
      return false
  }
  |> Async.StartAsTask
Run Code Online (Sandbox Code Playgroud)

死锁很难找到,因此在使用 F# 时,您应该尝试在应用程序中async仅调用一次,通常是在“main”方法中。Async.RunSynchronously