ASP.NET Identity的UserManager缓存用户?

时间:2018-03-07 14:26:20

标签: c# asp.net-mvc entity-framework asp.net-identity unity-container

我们在ASP.NET MVC 5.2,Entity Framework 6.2和Unity 5.7中使用ASP.NET Identity 2.2。

我们有一个类ConnectUserManager,它来自ASP.NET Identity UserManager。每次都会将新构建的UserStore传递给UserManager

ConnectUserManager(以及UserManager)的生命周期是每个请求:

Container.RegisterType<ConnectUserManager>(
    new PerRequestLifetimeManager(),
    new InjectionConstructor(
        Container.Resolve<ConnectDbContext>(),
        Container.Resolve<ITemplateManager>(),
        Settings.MaxFailedAccessAttemptsBeforeLockout,
        Settings.AccountLockoutTimeSpan));

当我们需要显示给定用户的详细信息时,控制器操作将检索用户:

public async Task<ActionResult> Details(int id)
{
    var user = await UserManager.FindByIdAsync(id);
    ...
}

其中UserManager是注入属性:

[Dependency]
public ConnectUserManager UserManager { get; set; }

问题是user似乎来自缓存:数据库中的修改似乎对我们的应用程序显示的内容没有任何影响。

此代码已投入生产一年,我们从未遇到任何问题:当我们的代码修改用户时,缓存似乎无效。

我们现在才注意到这个问题,因为当Identity将用户锁定时,它会更新用户的LockoutEndDateUtc属性,但似乎没有使缓存失效,我们得到一个陈旧的LockoutEndDateUtc值我们的展示。

我们做错了什么?

修改

@DotNetMatt在评论中将以下问题联系起来:
Entity Framework caching in aspnet Identity

除非我遗漏了某些内容,否则所接受的解决方案(无论如何写作)似乎与原始海报和我的问题完全无关。

然而,原始海报似乎自己找到了(a?)解决方案:&#34;我所做的是实现了我自己的用户界面并手动访问EF并使用.AsNoTracking()来避免缓存。&# 34;

有没有办法在不必重新实现(或子类化)用户存储的情况下执行此操作?

2 个答案:

答案 0 :(得分:1)

这是EF侥幸。身份没有任何内置缓存。 我怀疑你ConnectDbContext的生命时间镜是依赖的,而非每个请求。

一旦ConnectDbContext的实例返回实例o ApplicationUser,会发生什么。然后另一个ConnectDbContext实例执行锁定。但是当你回到ConnectDbContext的第一个实例时,它对其他东西所做的更新一无所知。因此,当您第二次获得相同的实例时,它不会进入数据库,它会返回已经跟踪过该用户的实例。

解决此问题的方法 - 确保您的生命周期范围与所涉及的所有活动部件相匹配:ConnectUserManagerUserStoreConnectDbContext。因此,无论何时从DB获取对象,它始终都是ConnectDbContext的同一个实例,为您提供此功能。

也是你链接的答案 - 看到最后的评论,OP说他有同样的范围问题。

答案 1 :(得分:1)

我发现了我的问题。 @trailmax是正确的(在他自己的回答的评论中),我有俘虏的依赖关系。

该错误实际上来自我的问题的代码片段,用于配置ConnectUserManager依赖项的注入:

Container.RegisterType<ConnectUserManager>(
    new PerRequestLifetimeManager(),
    new InjectionConstructor(
        Container.Resolve<ConnectDbContext>(),
        Container.Resolve<ITemplateManager>(),
        Settings.MaxFailedAccessAttemptsBeforeLockout,
        Settings.AccountLockoutTimeSpan));

与以下版本不同,此功能可以解决ConnectDbContext依赖关系一次

Container.RegisterType<ConnectUserManager>(
    new PerRequestLifetimeManager(),
    new InjectionFactory(
        container => new ConnectUserManager(
            container.Resolve<ConnectDbContext>(),
            container.Resolve<ITemplateManager>(),
            Settings.MaxFailedAccessAttemptsBeforeLockout,
            Settings.AccountLockoutTimeSpan)));

正确解析依赖关系每次构建新的ConnectUserManager