c# – UserManager在.Net身份中的奇怪行为

前端之家收集整理的这篇文章主要介绍了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);
    }
}

猜你在找的C#相关文章