ASP.NET核心身份.使用ApplicationDbContext和UserManager.他们共享上下文吗? [英] ASP.NET Core Identity. Using ApplicationDbContext and UserManager. Do they share the context?

查看:76
本文介绍了ASP.NET核心身份.使用ApplicationDbContext和UserManager.他们共享上下文吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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使用的相同吗?

谢谢.

解决方案

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

从ASP.NET Core Identity的EF Core默认实现的源代码中可以看到(

此处

/// <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的结果不是await,因此您需要更改为:

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

当然,首选使用 async-all-the-way ,并且您不应该使用.Wait()进行阻止.

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 awaiting 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().

这篇关于ASP.NET核心身份.使用ApplicationDbContext和UserManager.他们共享上下文吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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