Skip to content

UserManager.AddToRoleAsync() will throw InvalidOperationException because of entity already tracked #63296

@CoreDX9

Description

@CoreDX9

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

UserManager.AddToRoleAsync() will throw InvalidOperationException with message: The instance of entity type 'IdentityUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked..
All packages versioned 9.0.8.

Expected Behavior

Success to add user to role.

Steps To Reproduce

  1. Create an ASP.NET Core Razor pages application with Identity.
  2. Add RoleManager and api controllers to application. Edit Program.Main()
            builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>() // add this line
                .AddEntityFrameworkStores<ApplicationDbContext>();

            builder.Services.AddMvc(); // replace razor pages to mvc

            app.MapControllers(); // map api controller
  1. Add controller to call AddToRoleAsync()
[Route("api/[controller]")]
public class TestController : ControllerBase
{
    [HttpGet(nameof(AddRole))]
    public async Task<IActionResult> AddRole()
    {
        var roleManager = HttpContext.RequestServices.GetRequiredService<RoleManager<IdentityRole>>();

        if(!await roleManager.RoleExistsAsync("test"))
        {
            await roleManager.CreateAsync(new() { Name = "test" });
        }

        return Ok();
    }

    [HttpGet(nameof(AddToRole))]
    public async Task<IActionResult> AddToRole()
    {
        var requestProvider = HttpContext.RequestServices;

        IdentityUser? user = null;
        IdentityRole? role = null;
        await using (var scope = requestProvider.CreateAsyncScope())
        {
            var provider = scope.ServiceProvider;
            var userManager = provider.GetRequiredService<UserManager<IdentityUser>>();
            var roleManager = provider.GetRequiredService<RoleManager<IdentityRole>>();

            user = await userManager.FindByNameAsync("[email protected]");
            role = await roleManager.FindByNameAsync("test");
        }

        if (user != null && role != null)
        {
            // Use new scope to ensure not tracked.
            await using var scope = requestProvider.CreateAsyncScope();
            var provider = scope.ServiceProvider;
            var userManager = provider.GetRequiredService<UserManager<IdentityUser>>();

            var res = await userManager.AddToRoleAsync(user, role.Name!);
        }

        return Ok();
    }
}
  1. Register user named "[email protected]" using web page.
  2. Access endpoint "/api/test/addrole" to add role named "test".
  3. Access endpoint "/api/test/addtorole" to call AddToRoleAsync().

Exceptions (if any)

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The instance of entity type 'IdentityUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap1.Add(TKey key, InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NullableKeyIdentityMap1.Add(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable1 forceStateWhenUnknownKey, Nullable1 fallbackState)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode1 node) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode1 node, Func2 handleNode) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey) at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState) at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState) at Microsoft.EntityFrameworkCore.DbContext.Attach[TEntity](TEntity entity) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore9.UpdateAsync(TUser user, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.UserManager1.UpdateUserAsync(TUser user) at Microsoft.AspNetCore.Identity.UserManager1.AddToRoleAsync(TUser user, String role)
at TestUserRole.Controllers.TestController.AddToRole() in F:\source\repos\TestUserRole\TestUserRole\Controllers\TestController.cs:line 45
at TestUserRole.Controllers.TestController.AddToRole() in F:\source\repos\TestUserRole\TestUserRole\Controllers\TestController.cs:line 45
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

.NET Version

9.0.8

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-identityIncludes: Identity and providers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions