Ale*_*lex 13 c# asp.net entity-framework asp.net-identity
为了简化这个问题,我将描述更高级别的问题,然后根据需要进入任何实现细节.
我在开发中的应用程序中使用ASP.NET标识.在一系列请求的特定场景中,UserManager首先获取当前用户(至少一个FindById请求),其中获取用户.在随后的请求中,我更新了UserManager.Update保存的有关此用户的信息,我可以看到数据库中的更改仍然存在.
问题在于,在进一步的后续请求中,从FindById获取的用户对象不会更新.这很奇怪,但可能是UserManager中的缓存,我不明白.但是,当我跟踪数据库调用时,我看到UserManager确实正在将sql-requests发送到数据库以获取用户.
这就是它变得非常奇怪的地方 - 即使确认数据库是最新的,UserManager仍然以某种方式返回此过程中的旧对象.当我自己运行与数据库直接跟踪的完全相同的查询时,我会按预期获得更新的数据.
这个黑魔法是什么?
显然,某些东西被缓存在某个地方,但为什么它会对数据库进行查询,只是忽略它获得的更新数据?
例
下面的示例更新了db中对控制器操作的每个请求的所有内容,当GetUserDummyTestClass在另一个UserManager实例上调用findById时,我可以跟踪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);
}
Run Code Online (Sandbox Code Playgroud)
Test.cshtml
@model string
@{
var user = GetUserDummyTestClass.GetUser(Model);
}
@user.RealName;
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
更新
正如Erik指出的那样,我不应该使用静态UserManagers.但是,如果我保持GetUserDummyTest中的UserManager绑定到HttpContext(根据HttpRequest持久化),以防我想在请求期间多次使用它,它仍然缓存由Id获取的第一个User对象,并忽略任何更新来自另一个UserManager.因此,建议真正的问题确实是我使用两个不同的UserManagers作为trailmax建议,并且它不是为这种用法而设计的.
在上面的例子中,如果我将GetManager的GetManager继续保存在GetUserDummyTestClass中的UserManager,添加一个Update-method并且只在控制器中使用它,一切正常.
因此,如果得出结论,说明如果我想在控制器范围之外的UserManager中使用逻辑是正确的,我必须在适当的类中全局化UserManager实例,我可以将实例绑定到HttpContext,如果我想避免为一次性使用创建和处理实例?
更新2
进一步调查,我意识到我确实打算每个请求使用一个实例,并且实际上已经为Startup.Auth中的OwinContext设置了这个实例,之后像这样访问:
using Microsoft.AspNet.Identity.Owin;
// Controller
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()
// Other scopes
HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()
Run Code Online (Sandbox Code Playgroud)
这实际上是非常明显地看着提供的默认AccountController的设置,但我想上面描述的相当奇怪和意外的行为被证明是非常分散注意力的.尽管如此,理解这种行为的原因仍然很有趣,即使使用OwinContext.GetUserManager不再是问题.
Eri*_*sch 10
你的问题是,你使用两种不同的UserManager情况下,它看起来像他们都是静态定义(这是一个巨大的禁忌在Web应用程序,因为这些系统中的所有线程和用户之间共享,并且不线程安全,你甚至不能通过锁定它们使它们的线程安全,因为它们包含特定于用户的状态)
将您的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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3258 次 |
| 最近记录: |