C# ASP.NET Identity UserManager.CreateAsync()最近是否已更新,并出现了中断性更改?

C# ASP.NET Identity UserManager.CreateAsync()最近是否已更新,并出现了中断性更改?,c#,asp.net,asp.net-mvc,asp.net-identity,dapper,C#,Asp.net,Asp.net Mvc,Asp.net Identity,Dapper,几个月前,我创建了自己的ASP.NET Identity实现,覆盖UserStore以使用dapper和自定义sql连接,而不是实体框架。当时运作良好 现在我今天更新了所有的nuget软件包,从那以后我一直在解决问题。主要是当我通过调用var result=await UserManager.CreateAsync(user,newAccount.Password)注册一个新用户时它创建用户并执行所有其他检查,但随后抛出一个奇怪的错误,称操作无效。连接已关闭。 就好像UserManager.Cr

几个月前,我创建了自己的ASP.NET Identity实现,覆盖UserStore以使用dapper和自定义sql连接,而不是实体框架。当时运作良好

现在我今天更新了所有的nuget软件包,从那以后我一直在解决问题。主要是当我通过调用
var result=await UserManager.CreateAsync(user,newAccount.Password)注册一个新用户时它创建用户并执行所有其他检查,但随后抛出一个奇怪的错误,称
操作无效。连接已关闭。

就好像UserManager.CreateAsync有一个需要重写的新方法,但我完全不知道它可能是什么

以下是我实施的部分内容供参考:

客户控制员:

        [Authorize]
            public class AccountController : Controller
            {

                public UserManager<User> UserManager { get; private set; }
                public UserTokenProvider UserTokenProvider { get; set; }

                public AccountController() : this(new UserManager<User>(new UserStore(ConfigurationManager.ConnectionStrings["DBConn"].ConnectionString)))
                {
                }

                public AccountController(UserManager<User> userManager)
                {
                    UserManager = userManager;
                    UserManager.PasswordHasher = new NoPasswordHasher();

                }

...

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegistrationModel newAccount)
        {
            try
            {
                if (DbConfig.MaintenanceMode) return RedirectToAction("ComingSoon", "Home");
                if (ModelState.IsValid)
                {
                    var user = new User(newAccount);

                    var result = await UserManager.CreateAsync(user, newAccount.Password);
                    if (result.Succeeded)
                    {
                        await SignInAsync(user, isPersistent: false);
                        var userIn = await UserManager.FindByEmailAsync(newAccount.UserName);
                        if (!userIn.EmailConfirmed)
                        {
                            await SendValidationEmail(userIn);
                            return RedirectToAction("ConfirmationSent", new {userName = user.UserName});
                        }
                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        AddErrors(result);
                    }
                }

                // If we got this far, something failed, redisplay form
                return View(newAccount);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;

                return View(newAccount);
            }
        }
    public class UserStore : IUserStore<User>, IUserLoginStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>, IUserRoleStore<User>, IUserEmailStore<User>
        {
            private readonly string _dbConn;


            public UserStore(string conn = null)
            {
                if (conn != null)
                    _dbConn = conn;
                else
                    _dbConn = DbConfig.ConnectionString;
            }

            public void Dispose()
            {
            }



            public virtual Task CreateAsync(User user)
            {
                using (var _conn = new SqlConnection(_dbConn))
                {
                    if (_conn.State == ConnectionState.Closed) _conn.Open();
                    return _conn.ExecuteAsync("users_UserCreate",
                        new
                        {
                            @UserId = user.Id,
                            @UserName = user.UserName,
                            @PasswordHash = user.PasswordHash,
                            @SecurityStamp = user.SecurityStamp
                        }, commandType: CommandType.StoredProcedure);

                }
            }

... Remaining methods omitted for brevity ...
[授权]
公共类AccountController:控制器
{
公共用户管理器用户管理器{get;private set;}
公共UserTokenProvider UserTokenProvider{get;set;}
public AccountController():这是(新的UserManager(新的UserStore(ConfigurationManager.ConnectionStrings[“DBConn”].ConnectionString)))
{
}
公共帐户控制器(用户管理器用户管理器)
{
UserManager=UserManager;
UserManager.PasswordHasher=new NoPasswordHasher();
}
...
[HttpPost]
[异名]
[ValidateAntiForgeryToken]
公共异步任务寄存器(RegistrationModel newAccount)
{
尝试
{
如果(DbConfig.MaintenanceMode)返回RedirectToAction(“即将到来”、“主页”);
if(ModelState.IsValid)
{
var user=新用户(newAccount);
var result=await UserManager.CreateAsync(用户,newAccount.Password);
if(result.successed)
{
等待信号同步(用户,ispersist:false);
var userIn=await UserManager.findbyemailsync(newAccount.UserName);
如果(!userIn.emailconfirm)
{
等待SendValidationEmail(userIn);
返回RedirectToAction(“确认”,新的{userName=user.userName});
}
返回重定向到操作(“索引”、“主页”);
}
其他的
{
加法器(结果);
}
}
//如果我们走到这一步,有些东西失败了,重新显示形式
返回视图(新帐户);
}
捕获(例外情况除外)
{
var msg=例如消息;
返回视图(新帐户);
}
}
用户商店:

        [Authorize]
            public class AccountController : Controller
            {

                public UserManager<User> UserManager { get; private set; }
                public UserTokenProvider UserTokenProvider { get; set; }

                public AccountController() : this(new UserManager<User>(new UserStore(ConfigurationManager.ConnectionStrings["DBConn"].ConnectionString)))
                {
                }

                public AccountController(UserManager<User> userManager)
                {
                    UserManager = userManager;
                    UserManager.PasswordHasher = new NoPasswordHasher();

                }

...

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegistrationModel newAccount)
        {
            try
            {
                if (DbConfig.MaintenanceMode) return RedirectToAction("ComingSoon", "Home");
                if (ModelState.IsValid)
                {
                    var user = new User(newAccount);

                    var result = await UserManager.CreateAsync(user, newAccount.Password);
                    if (result.Succeeded)
                    {
                        await SignInAsync(user, isPersistent: false);
                        var userIn = await UserManager.FindByEmailAsync(newAccount.UserName);
                        if (!userIn.EmailConfirmed)
                        {
                            await SendValidationEmail(userIn);
                            return RedirectToAction("ConfirmationSent", new {userName = user.UserName});
                        }
                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        AddErrors(result);
                    }
                }

                // If we got this far, something failed, redisplay form
                return View(newAccount);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;

                return View(newAccount);
            }
        }
    public class UserStore : IUserStore<User>, IUserLoginStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>, IUserRoleStore<User>, IUserEmailStore<User>
        {
            private readonly string _dbConn;


            public UserStore(string conn = null)
            {
                if (conn != null)
                    _dbConn = conn;
                else
                    _dbConn = DbConfig.ConnectionString;
            }

            public void Dispose()
            {
            }



            public virtual Task CreateAsync(User user)
            {
                using (var _conn = new SqlConnection(_dbConn))
                {
                    if (_conn.State == ConnectionState.Closed) _conn.Open();
                    return _conn.ExecuteAsync("users_UserCreate",
                        new
                        {
                            @UserId = user.Id,
                            @UserName = user.UserName,
                            @PasswordHash = user.PasswordHash,
                            @SecurityStamp = user.SecurityStamp
                        }, commandType: CommandType.StoredProcedure);

                }
            }

... Remaining methods omitted for brevity ...
公共类用户存储:IUserStore、IUserLoginStore、IUserPasswordStore、IUserSecurityStampStore、IUserRoleStore、IUserEmailStore
{
私有只读字符串_dbConn;
公共用户存储(字符串conn=null)
{
如果(conn!=null)
_dbConn=conn;
其他的
_dbConn=DbConfig.ConnectionString;
}
公共空间处置()
{
}
公共虚拟任务CreateAsync(用户)
{
使用(var _conn=newsqlconnection(_dbConn))
{
如果(_conn.State==ConnectionState.Closed)_conn.Open();
返回_conn.ExecuteAsync(“用户创建”,
新的
{
@UserId=user.Id,
@UserName=user.UserName,
@PasswordHash=user.PasswordHash,
@SecurityStamp=user.SecurityStamp
},commandType:commandType.StoredProcess);
}
}
…为简洁起见,省略了其余方法。。。
您会注意到UserStore.CreateAsync()函数有
if(_conn.State==ConnectionState.Closed)\u conn.Open();
,因为这是多个线程关于连接关闭错误的建议。即使没有这一行,查询也可以正常工作,并将新用户正确插入数据库

错误来自UserManager.CreateAsync()调用UserStore.CreateAsync()之后的某个地方


知道缺少了什么吗?

答案是否定的,ASP.NET身份没有随着不断的变化而改变

使用DotNetPeek,我查看了标识库,以了解在UserManager.CreateAncy()期间调用了哪些方法,它只调用UserStore.CreateSync和密码更新

在反复使用代码之后,我突然意识到,在等待UserManager.CreateSync的同时,对UserStore.CreateSync的内部调用并不是必须重写
公共虚拟任务CreateAsync(User-User)
由于必须返回一个未等待的任务,因此我们必须在返回任务之前处理一些代码以等待Dapper的响应

下面是更新后的UserStore.CreateAsync覆盖。注意:
如果(\u conn.State==ConnectionState.Closed)\u conn.Open();
实际上不需要,因为在方法完成之前连接已经关闭,Dapper在处理连接方面做得非常出色

public virtual Task CreateAsync(User user)
{
    using (var _conn = new SqlConnection(_dbConn))
    {
        var result = _conn.ExecuteAsync("users_UserCreate", new
                    {
                        @UserId = user.Id,
                        @UserName = user.UserName,
                        @PasswordHash = user.PasswordHash,
                        @SecurityStamp = user.SecurityStamp
                    }, commandType: CommandType.StoredProcedure).ConfigureAwait(true);

        return Task.FromResult(result);
    }
}

希望这将有助于将来面临同样问题的其他人。

在netcore 2.1.302上,如果我们不等待CreateAync执行,它将在Azure和本地SqlServer中引发异常。在这种情况下,它是一个种子clas,具有