DetectChanges when using AspNet.Identity UserManager

Viewed 865

I am using AspNet.Identity for User Management in my MVC project because I believe it is a great start, now that I have it working (with little changes), I wanted to add an Audit Trail (Track Changes) like my other DbContext that I use.

In IdentityModel.cs, I have the following code that works, but only in certain situations:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
        //Can't recall if this was there by default
        Configuration.AutoDetectChangesEnabled = true;
    }

    public override int SaveChanges()
    {
        //Tell EF to Track Changes
        ChangeTracker.DetectChanges();

        //More code once I get this working
        //
    }

}

In my Controller, I have the following:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(EditUserViewModel editUser)
{
    var user = await UserManager.FindByIdAsync(editUser.Id);

    //Update a property within the User object
    user.FirstName = "Updated First Name";

    //Save to database
    var result = UserManager.Update(user);
    //The above saves to database, but doesn't trigger SaveChanges()

    //SaveChanges() will be triggered if I call
    HttpContext.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();

}

When the above HttpContext.GetOwinContext().Get<ApplicationDbContext>().SaveChanges(); is called, the updated ApplicationUser has an EntityState of Unchanged. Makes sense as it was already saved.

However, I am trying to see how I can utilize the UserManager and still work with SaveChanges().

I also understand that I could write a class that would log all of this myself, but as I expand the ApplicationUser (or ApplicationRole) I would like to avoid the extra coding for the Audit Log.

Any advice or links would help!

1 Answers

Set AutoSaveChanges to false in the constructor of your UserStore (which you would pass to the constructor of the UserManager).

public class MyUserStore : UserStore<User, Role, int, UserLogin, UserRole, UserClaim>
    {
        private MyDbContext _context;
        public MyUserStore(MyDbContext context) : base(context)
        {
            //Set this to false
            AutoSaveChanges = false;
            _context = context;
        }
    }

Now you can call save changes as you normally would and the change tracker will contain the changes you're expecting.

I did however encounter an OptimisticConcurrencyException when I tried to make more than one call to UserManager between calls to SaveChanges. I just called SaveChanges after each UserManager operation.

Related