c# – UserManager在.Net身份中的奇怪行为
为了简化这个问题,我将描述更高级别的问题,然后在需要时进入任何实现细节.
我正在开发的应用程序中使用ASP.NET身份.在一系列请求的特定场景中,UserManager首先获取当前用户(至少一个FindById请求),该用户被提取.在随后的请求中,我更新UserManager.Update保存的此用户的信息,我可以看到数据库中持久存在更改. 问题在于,在进一步的后续请求中,从FindById获取的用户对象不会更新.这是奇怪的,但可能是关于缓存在UserManager我不明白的东西.但是,当我跟踪数据库调用时,我发现UserManager确实发送sql请求到数据库以获取用户. 这是真的很奇怪 – 即使数据库被确认为最新,UserManager仍然以某种方式从此进程返回一个旧对象.当我自己运行完全相同的查询直接跟踪到数据库时,我按预期得到更新的数据. 这是什么黑魔法? 显然,某些东西被缓存在某个地方,但是为什么会对数据库进行查询,只是为了忽略更新的数据? 例 下面的示例将针对控制器操作的每个请求更新db中的所有内容,并且当GetUserDummyTestClass在UserManager的另一个实例上调用findById时,我可以跟踪sql请求,并可以直接测试这些请求并确认它们返回更新数据.但是,从同一行代码返回的用户对象仍然具有旧值(在这种情况下,应用程序启动后的第一个编辑,无论调用了多少次测试操作). 调节器 public ActionResult Test() { var userId = User.Identity.GetUserId(); var user = UserManager.FindById(userId); user.RealName = "name - " + DateTime.Now.ToString("mm:ss:fff"); UserManager.Update(user); return View((object)userId); } Test.cshtml @model string @{ var user = GetUserDummyTestClass.GetUser(Model); } @user.RealName; GetUserDummyTestClass public class GetUserDummyTestClass { private static UserManager<ApplicationUser> _userManager; private static UserManager<ApplicationUser> UserManager { get { return _userManager ?? (_userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))); } } public static ApplicationUser GetUser(string id) { var user = UserManager.FindById(id); return user; } } 更新 正如Erik指出的那样,我不应该使用静态用户管理器.但是,如果我将UserManager放在GetUserDummyTest中,绑定到HttpContext(在HttpRequest中持久化),以防在请求期间使用它多次,那么它仍然会缓存第一个使用Id的User对象,并忽略任何更新从另一个UserManager.因此,表明真正的问题确实是我使用两个不同的UserManager作为trailmax建议,并且它不是为这种用法设计的. 在我上面的例子中,如果我将UserManager放在GetUserDummyTestClass中,通过HttpRequest持久化,添加一个Update方法,并且只在控制器中使用它,一切都按预期运行正常. 因此,如果要得出结论,说明如果我想使用来自控制器范围之外的UserManager的逻辑,我必须将UserManager实例全局化在适当的类中,我可以将实例绑定到HttpContext,如果我想避免创建和处理实例一次性使用? 更新2 再次进一步调查,我意识到我确实是为每个请求使用一个实例,而且这实际上是为Startup.Auth中的OwinContext设置的,之后访问过如下: using Microsoft.AspNet.Identity.Owin; // Controller HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>() // Other scopes HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>() 这实际上令人尴尬的是看到设置了默认的AccountController,但我猜想上面说的相当奇怪和意想不到的行为证明是分心的.不过,了解这种行为的原因,即使OwinContext.GetUserManager不再是问题了,这是很有趣的. 解决方法
您的问题是您正在使用两个不同的UserManager实例,它们看起来像是静态定义的(这在Web应用程序中是一个巨大的no-no,因为这些都是在系统的所有线程和用户之间共享的,而不是线程安全,你甚至不能通过锁定它们来使线程安全,因为它们包含特定于用户的状态)
将您的GetUserDummyTestClass更改为: private static UserManager<ApplicationUser> UserManager { get { return new UserManager<ApplicationUser>( new UserStore<ApplicationUser>(new ApplicationDbContext())); } } public static ApplicationUser GetUser(string id) { using (var userManager = UserManager) { return UserManager.FindById(id); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |