I'm building a project in EF6 and aspnet Identity.
I'm facing the following problem:
if I call
var account = await FindByNameAsync(userName); // account.IsConfirmed = true
I get the account I'm looking for (example: 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
I've tried adding the following in my DbContext constructor
> this.Configuration.ProxyCreationEnabled = false;
> this.Configuration.LazyLoadingEnabled = false;
But this didn't change anything.
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?
Thanks!
EDIT: added dbContext info
My IoC (Unity)
container.RegisterType<IUnitOfWork, UserManagementContext>(new HttpContextLifetimeManager<IUnitOfWork>());
container.RegisterType<IUserStore<Account>, UserStore<Account>>(new InjectionConstructor(container.Resolve<IUnitOfWork>()));
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();
}
}
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;
}
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;
}
}
UPDATE:
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.
UPDATE 2 In case anyone has this problem as well: the problem was not aspnet Identity, it's EF.
What I did was implemented my own userstore and manually accessed EF and used .AsNoTracking() to avoid the caching.
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.
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 !!!
Instead you should preserve your HttpContext and use it inside your async code as shown below.
Plain Old Inheritance
I would recommend using abstract entity controller pattern, which is easy to use in async mode.
Derive your controller accordingly like,
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.