UserManager ResetPasswordAsync 异常“键值已被跟踪”

问题描述 投票:0回答:1

我正在尝试在

ResetPasswordAsync
上使用
Microsoft.AspNetCore.Identity.UserManager
方法重置用户的密码。

// Inject the UserManager
[Inject] public UserManager<ApplicationManager> UserManager { get; set; }

// Inject the factory
[Inject] public IDbContextFactory<DataContext> Factory { get; set; }

...

// Reset the password
async Task ResetPasswordAsync (ApplicationUser user)
{
    ...
    
    var context = Factory.CreateDbContext();

    var password = CreatePassword();
    var token = await UserManager.GeneratePasswordResetTokenAsync(user);
    
    // Tried setting the state to detached, but it didn't work
    dataContext.Entry(user).State = EntityState.Detached;

    // This line throws the exception
    await userManager.ResetPasswordAsync(user, token, password );

}

但是,最后一行抛出了这个异常。

无法跟踪实体类型“ApplicationUser”的实例,因为已跟踪具有该键值的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

我使用实体框架核心作为数据上下文,使用 blazor 作为用户界面。

c# entity-framework-core asp.net-core-identity
1个回答
0
投票

作为一般规则,避免传递分离的实体,它会导致许多这样的问题。

当你有这样的代码时:

var token = await UserManager.GeneratePasswordResetTokenAsync(user);

您正在传递传递到方法中的分离的“用户”引用。相反,简化。如果您的方法只有用户 ID,您会做什么?

async Task ResetPasswordAsync (int userId)
{
    var user = await UserManager.FindByIdAsync(userId);
    var password = CreatePassword();
    var token = await UserManager.GeneratePasswordResetTokenAsync(user);

    await userManager.ResetPasswordAsync(user, token, password );
}

这段代码可能会按预期工作。作为在以下位置传递用户引用的解决方法:

async Task ResetPasswordAsync (ApplicationUser currentUser)
{
    var user = await UserManager.FindByIdAsync(currentUser.UserId);
    var password = CreatePassword();
    var token = await UserManager.GeneratePasswordResetTokenAsync(user);

    await userManager.ResetPasswordAsync(user, token, password );
}

本质上使用

UserManager
及其底层
DbContext
实例所熟悉的 User 实例引用,而不是分离的引用。

将分离用户传递到方法中的问题在于,虽然您可以将该分离引用传递给像

GeneratePasswordResetToken
这样的方法,但
UserManager
很可能会使用该 User 引用创建一个 Token 实例。
UserManager
DbContext
可能已加载并且仍在跟踪对用户的引用,因此当您使用该分离引用保存用户/令牌时,最终可能会收到底层
DbContext 的错误
正在跟踪参考。

简而言之,为了避免此类问题,请设计避免将实体传递到超出读取它们的

DbContext
范围之外。对于 Blazor 和 WPF 应用程序来说,这可能会很棘手,因为在使用注入的
DbContext
实例时,边界没有明确定义。如果您确实有理由使用分离实体,那么您必须小心检查它们是否被底层
DbContex
t 跟踪,如果是,则替换这些引用。解决方案是 not
DbContextFactory
,因为它肯定会返回一个新的
DbContext
实例,您需要
DbContext
引用,在这种情况下
UserManager
将配置为使用。 (注入到
UserManager
中的内容)因此,在这种情况下,更快的修复方法是从
UserManager
中获取用户引用。

© www.soinside.com 2019 - 2024. All rights reserved.