【问题标题】:ASP.NET Core Identity. Using ApplicationDbContext and UserManager. Do they share the context?ASP.NET 核心标识。使用 ApplicationDbContext 和 UserManager。他们是否共享上下文?
【发布时间】:2018-07-09 05:48:06
【问题描述】:

我在 ASP.NET MVC Core 2 应用程序中有一个数据库初始化方法。 在那个方法中,我使用 ApplicationDbContext 和 UserManager 来初始化数据库。 我从构造函数的依赖注入中获得了这两个实例:

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

我想知道的是它们是否共享相同的上下文实例,或者是否为 ApplicationDbContext 创建了一个上下文,而为 UserManager 创建了另一个上下文。 如果我执行这样的操作:

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();

在 CreateAsync 调用之后立即在数据库中创建用户。

但是,如果我这样更新用户:

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

在调用 UpdateAsync 之后,数据库中没有任何更新。用户名依然是“test”。

但是,如果然后我执行:

context.SaveChanges();

应用更改并更新数据库。

那么,为什么 CreateAsync 方法“保存其更改”而不显式调用“context.SaveChanges”而 UpdateAsync 方法需要它?我通过依赖注入获得的 ApplicationDbContext 实例是否与 CreateAsync 使用的相同?

谢谢。

【问题讨论】:

  • 它们在请求范围内使用相同的上下文。
  • 也不要进行阻塞调用.Wait(),在异步方法中使用await,否则会有死锁的风险。

标签: c# asp.net-core asp.net-identity


【解决方案1】:

Entity Framework Core 在 ASP.NET Core 应用程序中的默认注册是每个请求的范围,因此它们将最终共享上下文。

从 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;
}

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;
}

,它们都保存更改。

你遇到的问题是UpdateAsync的结果你不是awaiting,所以你需要改成:

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

当然,使用 async-all-the-way 是首选版本,您不应使用 .Wait() 阻止。

【讨论】:

  • 我会更快地建议不要完全使用该阻塞调用。
  • 即使他没有await 调用UpdateAsync,它不应该将更改保存到数据库吗?代码不会等到保存命令完成,但我相信它应该保存。
  • @Alisson 这完全取决于调用UpdateAsync 后会发生什么。如果请求在此处结束,则上下文可能会在有机会保存更改之前被丢弃
  • 非常感谢。我正在使用 .Wait() 调用,因为这是一个 DB Initializer 方法,作为从 Program.Main 调用的 WebHost 的扩展完成;所以这里没有 await 可用。无论如何,那是主要用于测试的开发代码。
  • @MorgoZ 在这种情况下最好使用Task.Run(async () =&gt; await userManager.UpdateAsync(adminTeacherUser)).GetAwaiter().GetResult(),而不是仅仅调用Wait()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 2015-05-17
  • 2011-12-27
  • 1970-01-01
相关资源
最近更新 更多