我正在开发的应用程序中使用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不再是问题了,这是很有趣的.
解决方法
将您的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); } }