UserManager.Update(user) method isn't thread safe

可紊 提交于 2020-01-05 04:05:14

问题


I'm trying to update a user with UserManager in a controller. Just before I update the user, a call to an external service fires a webhook that tries to update the same user, also using UserManager. But that's a different request and a different part of the application (the "webhook controller").

Here's the exception I got while debugging in the controller:

System.Data.Entity.Core.EntityException. "An error occurred while starting a transaction on the provider connection. See the inner exception for details." New transaction is not allowed because there are other threads running in the session.

Here's the code, which is the same in the controller and the "webhook controller", except for a different property being set:

AppUserManager appUserManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();

AppUser member = appUserManager.FindById(User.Identity.GetUserId());

member.Email = newEmail;

IdentityResult identityResult = appUserManager.Update(member);

AppUserManager is created like this:

public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext owinContext)
{           

    EFDbContext db = owinContext.Get<EFDbContext>();

    AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));

    // etc.

    return manager;
}

I'm a little confused about what's happening here. Am I getting this error because both instances of AppUserManager are getting the EFDbContext from the OwinContext? I'm not even sure how that works.

Would it help to replace

EFDbContext db = owinContext.Get<EFDbContext>();

with

 EFDbContext db = new EFDbContext();

But according to this: https://blogs.msdn.microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in-asp-net-identity/

that's not a good idea because:

"In the current approach, if there are two instances of the UserManager in the request that work on the same user, they would be working with two different instances of the user object. An example for this would be using the one in the class property and instantiating one locally in the method under execution. In this scenario the changes made by either of them would not reflect the changes made by the other. Hence persisting these changes back to the database would lead to incorrect changes being made to the user object."

Do I need to wrap the update in some sort of transaction or using block? I don't see how I can be getting this error.

Here's the configuration:

public void Configuration(IAppBuilder app)
{
    DataProtectionProvider = app.GetDataProtectionProvider(); 

    app.CreatePerOwinContext<EFDbContext>(EFDbContext.Create);

    app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);

    app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create); 
}

来源:https://stackoverflow.com/questions/43037450/usermanager-updateuser-method-isnt-thread-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!