为了简化这个问题,我将描述更高级别的问题,然后根据需要进入任何实现细节。用户管理器在.Net标识中的奇怪行为
我在开发中使用我的应用程序中的ASP.NET身份。在一系列请求的特定场景中,UserManager首先获取当前用户(至少一个FindById请求),用户被抓取到。在后续的请求中,我更新了由UserManager.Update保存的此用户的信息,我可以看到数据库中保留的更改。
问题在于,在进一步的后续请求中,从FindById获取的用户对象不会更新。这很奇怪,但可能是关于在UserManager中缓存的内容我不明白。但是,当我跟踪数据库调用时,我发现UserManager确实正在向数据库发送sql-requests以获取用户。
这就是它真正奇怪的地方 - 即使数据库被确认为最新的,UserManager仍然以某种方式从这个过程中返回一个旧对象。当我自己运行直接跟踪到数据库的完全相同的查询时,我按预期得到更新的数据。
这是什么黑魔法?
很明显,某些东西被缓存在某处,但为什么它会对数据库进行查询,只是为了忽略它所获取的更新数据?
例
此示例下面更新一切按预期在db为每个请求到控制器的动作,和时GetUserDummyTestClass呼吁findById上的UserManager的另一实例我可以跟踪SQL请求,并能直接测试这些数据库并验证它们是否返回更新的数据。但是,从同一行代码中返回的用户对象仍然具有旧值(在这种情况下,应用程序启动后的第一次编辑,无论调用Test操作多少次)。
控制器
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指出的,我不应该使用静态UserManagers。但是,如果我保持UserManager在GetUserDummyTest中绑定到HttpContext(每个HttpRequest持久化它),以防在请求期间多次使用它,它仍然缓存它通过Id获取的第一个User对象,并忽略任何更新从另一个用户管理器。因此表明真正的问题确实是我使用两种不同的UserManagers作为trailmax建议的,并且它不是为这种用法而设计的。
在我上面的示例中,如果我将UserManager保留在GetUserDummyTestClass持久性HttpRequest上,请添加Update-method并仅在控制器中使用它,一切正常。
因此,如果要得出结论,说明如果我想使用控制器范围之外的UserManager中的逻辑,我必须将UserManager实例全局化为可绑定的适当类HttpContext的实例,如果我想避免创建和处置一次性使用的实例?
更新2
调查远一点,我意识到,我确实打算每个请求使用一个实例,这实际上已经被设置为OwinContext在Startup.Auth后来像访问这样的:
using Microsoft.AspNet.Identity.Owin;
// Controller
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()
// Other scopes
HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()
这实际上是令人尴尬的明显看提供的默认的AccountController的设置,但我想以上证明:相当分散描述的相当奇怪和意外的行为。不过,理解这种行为的原因是很有趣的,尽管使用OwinContext.GetUserManager不会再成为问题了。
我知道一个人应该在发布了一个新问题后,我会在一段时间后挂断,但不幸的是,我的时区迫使我暂时离开。如果有人有问题,请耐心等待。 – Alex 2014-09-06 16:25:31
你可以发布一个示例代码来重现你的问题吗? – trailmax 2014-09-07 16:54:02
@trailmax更新 – Alex 2014-09-08 16:15:08