ASPNET Identity中的实体框架缓存 [英] Entity Framework caching in aspnet Identity

查看:75
本文介绍了ASPNET Identity中的实体框架缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用EF6和aspnet Identity构建一个项目.

I'm building a project in EF6 and aspnet Identity.

我面临以下问题:

如果我打电话

var account = await FindByNameAsync(userName); // account.IsConfirmed = true

我得到了我要寻找的帐户(例如:isConfirmed = true).

I get the account I'm looking for (example: isConfirmed = true).

当我手动更改数据库中的值(isConfirmed = true-> isConfirmed = false)并再次运行查询时,我仍然得到旧帐户对象(isConfirmed = true)

When I manually change a value in my database (isConfirmed = true -> isConfirmed = false) and I run my query again, I still get my old account object (isConfirmed = true)

var account = await FindByNameAsync(userName); // Should be account.IsConfirmed = false, but still gives me IsConfirmed = true

我尝试在DbContext构造函数中添加以下内容

I've tried adding the following in my DbContext constructor

> this.Configuration.ProxyCreationEnabled = false;
> this.Configuration.LazyLoadingEnabled = false;

但这并没有改变任何东西.

But this didn't change anything.

对此我该怎么办?缓存的数据会保留多长时间? 我看过的所有帖子都要求您运行查询(从..中的..),但是看到我如何使用aspnet Identity并且我无法控制这些事情,该怎么办?

What can I do about this? How long does the cached data remain? All the posts I've seen, require you to run the query (from .. in ..), but seeing how I'm using aspnet Identity and I have no control over these things, what can I do?

谢谢!

添加了dbContext信息

added dbContext info

我的IoC(团结)

container.RegisterType<IUnitOfWork, UserManagementContext>(new HttpContextLifetimeManager<IUnitOfWork>());
container.RegisterType<IUserStore<Account>, UserStore<Account>>(new InjectionConstructor(container.Resolve<IUnitOfWork>()));

HttpContextLifeTimeManager:

HttpContextLifeTimeManager:

public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{
    public override object GetValue()
    {
        return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
    }

    public override void SetValue(object newValue)
    {
        HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
    }

    public override void RemoveValue()
    {
        HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
    }

    public void Dispose()
    {
        RemoveValue();
    }
}

我的IUnitOfWork

My IUnitOfWork

public interface IUnitOfWork : IDisposable
{
    void Save();
    Task SaveAsync();
    DbSet<TEntity> EntitySet<TEntity>() where TEntity : class;
    void MarkAsModified<TEntity>(TEntity entity) where TEntity : class;
}

我的UserManagementContext

My UserManagementContext

public class UserManagementContext : IdentityDbContext<Account>, IUnitOfWork
{
    static UserManagementContext()
    {
        //Database.SetInitializer<UserManagementContext>(new RecreateDatabase());
        Database.SetInitializer<UserManagementContext>(null);
    }

    public UserManagementContext()
        : base("Name=UserManagementConnection")
    {
        this.Configuration.ProxyCreationEnabled = false;
        this.Configuration.LazyLoadingEnabled = false;
    }

    // ... (my Dbsets)

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // configuration ..
    }

    public void Save()
    {
        SaveChanges();
    }

    public async Task SaveAsync()
    {
        await SaveChangesAsync();
    }

    public DbSet<TEntity> EntitySet<TEntity>() where TEntity : class
    {
        return this.Set<TEntity>();
    }

    public void MarkAsModified<TEntity>(TEntity entity) where TEntity : class
    {
        this.Entry(entity).State = EntityState.Modified;
    }
}

更新:

我发现了另外一件奇怪的事情.当我设置我的上次登录日期字段时,该更改会被拾取,但是当我设置我的isConfirmed字段时,则不会被拾取..(数据库更改实际上会被缓存的数据覆盖!

I discovered another strange thing. When I set my last login date field, that change gets picked up, but when I set my isConfirmed field, that doesn't get picked up.. (the DB change actually gets overwriten by the cached data!

因此,这确认了通过代码输入的数据将被保留,但是数据库中的手动更改将被忽略.

So this confirms that data entered via code get persisted, but manual changes in the DB get ignored.

更新2 如果有人也有这个问题:问题不是aspnet身份,那是EF.

UPDATE 2 In case anyone has this problem as well: the problem was not aspnet Identity, it's EF.

我所做的是在自己的用户存储区中实现的,并手动访问了EF并使用.AsNoTracking()来避免缓存.

What I did was implemented my own userstore and manually accessed EF and used .AsNoTracking() to avoid the caching.

推荐答案

HttpContext.Current在异步编程中是有害的.

HttpContext.Current is evil in Async programming.

同步或更早的代码每个线程只能执行一个上下文和一个控制器的方法.因此没有冲突.

Synchronous or earlier code would only execute methods of one context and one controller per thread. So there was no conflict.

在异步编程中,多个控制器实例的方法在同一线程上执行.所以HttpContext.Current的值与您想象的不一样,很脏!!!

In asynchronous programming, methods of multiple controller instances are executed on same thread. So value of HttpContext.Current is not same as you think, it is dirty !!!

相反,您应该保留HttpContext并在异步代码中使用它,如下所示.

Instead you should preserve your HttpContext and use it inside your async code as shown below.

public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{

    private HttpContext Context; 

    public HttpContextLifetimeManager(HttpContext context){
        this.Context = context;
    }

    public override object GetValue()
    {
        return Context.Items[typeof(T).AssemblyQualifiedName];
    }

    public override void SetValue(object newValue)
    {
        Context.Items[typeof(T).AssemblyQualifiedName] = newValue;
    }

    public override void RemoveValue()
    {
        Context.Items.Remove(typeof(T).AssemblyQualifiedName);
    }

    public void Dispose()
    {
        RemoveValue();
    }
}


container.RegisterType<IUnitOfWork, UserManagementContext>(
   new HttpContextLifetimeManager<IUnitOfWork>(this.ControllerContext.HttpContext)); 

普通旧继承

我建议使用抽象实体控制器模式,该模式在异步模式下易于使用.

I would recommend using abstract entity controller pattern, which is easy to use in async mode.

public abstract class EntityController<TDbContext> : Controller
   where TDbContext: DbContext
{

    protected TDbContext DB { get; private set;}

    public EntityController(){
        DB = Activator.CreateInstance<TDbContext>();
    }

    protected override void OnDispose(){
        DB.Dispose();
    }
}

相应地派生您的控制器,

Derive your controller accordingly like,

public class UserController : EntityController<UserManagementContext>
{


    public async Task<ActionResult> SomeMethod(){
        ......
        var user = await DB.FindByNameAsync(userName);
        ......
    }

}

如果您仍然想使用Unity,则必须为每个请求创建新的unity实例,但这只是浪费CPU周期.我认为在MVC中使用Unity来完成更简单的任务只是编程.如果抽象类很容易做到这一点.异步编程有很多新东西,Unity并不是为此而设计的.

If you still want to use Unity then you will have to create new unity instance per request, but that is just waste of CPU cycle. In my opinion using Unity in MVC for simpler task is just over programming. If something that is easily done with abstract classes. Asynchronous programming has lot of new things, Unity was not designed for that.

这篇关于ASPNET Identity中的实体框架缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆