简体   繁体   中英

ASP.NET Core Identity. Using ApplicationDbContext and UserManager. Do they share the context?

i have an database initialization method in an ASP.NET MVC Core 2 application. In that method i'm using ApplicationDbContext and UserManager to initialize the database. I get both instances from the constructor's dependency injection:

public static void Initialize(ApplicationDbContext context,
            UserManager<ApplicationUser> user)

What i want to know is if they share the same context instance or if one context is created for ApplicationDbContext and another for UserManager. If i execute something like this:

ApplicationUser adminTeacherUser = new ApplicationUser
            {
                UserName = "test@test.com",
                Email = "test@test.com",
                EmailConfirmed = true,
                Name = "test",
                LastName = "test",
                BirthDate = null,
                EntryDate = DateTime.Now                    
            };

            userManager.CreateAsync(adminTeacherUser, "password").Wait();

The user is created at database inmediatly after the CreateAsync call.

But, if then i update the user like this:

adminTeacherUser.Name = "other";                
userManager.UpdateAsync(adminTeacherUser);

After the call to UpdateAsync nothing is updated at the database. The name of the user stills being "test".

But, if then i execute:

context.SaveChanges();

The changes are applied and the database is updated.

So, why the CreateAsync method "saves its changes" without explicitly calling "context.SaveChanges" and the UpdateAsync method needs it? Is the ApplicationDbContext instance i get by dependency injection the same that CreateAsync is using?

Thank you.

The default registration of Entity Framework Core in an ASP.NET Core application is a per-request scope, so they will definitively share the context.

As you can see from the source code of the default implementation of EF Core for ASP.NET Core Identity ( here

/// <summary>
/// Creates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the creation operation.</returns>
public async override Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
    cancellationToken.ThrowIfCancellationRequested();
    ThrowIfDisposed();
    if (user == null)
    {
        throw new ArgumentNullException(nameof(user));
    }
    Context.Add(user);
    await SaveChanges(cancellationToken);
    return IdentityResult.Success;
}

and here

/// <summary>
/// Updates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the update operation.</returns>
public async override Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
    cancellationToken.ThrowIfCancellationRequested();
    ThrowIfDisposed();
    if (user == null)
    {
        throw new ArgumentNullException(nameof(user));
    }

    Context.Attach(user);
    user.ConcurrencyStamp = Guid.NewGuid().ToString();
    Context.Update(user);
    try
    {
        await SaveChanges(cancellationToken);
    }
    catch (DbUpdateConcurrencyException)
    {
        return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
    }
    return IdentityResult.Success;
}

, they both save changes.

The problem you are experiencing is that you are not await ing for the result of UpdateAsync , so you need to change to:

await userManager.UpdateAsync(adminTeacherUser);
//or
userManager.UpdateAsync(adminTeacherUser).Wait();

Of course, using async-all-the-way is the preferred version and you shouldn't block using .Wait() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM