MVC5: UserManager.AddToRole(): "Error Adding User to Role: UserId not found"?

19,153

Solution 1

I am leaving this here for anyone that might have had a similar issue. I had exactly the same "symptoms". It turns out that the problem related to the password being stored not adhering to the configured password policy (at least one uppercase char, one lowercase char, etc etc).

As per below comments and answers, in general, the same vague error message is thrown when any of the user creation constraints or policies are not followed.

This might include the following:

  • Password policy not followed (this seems to be the most common cause)
  • Required fields being passed through as empty strings / null
  • Duplicate username or email

There is really a wide range of issues which can cause this error to occur. If the above does not solve your problem, I suggest the following:

  1. Familiarize yourself with the rules and policies for identityprovider as it was set up for your solution
  2. As per @Ted's answer below, trace or put a breakpoint on the UserManager.Create method to view the result, as this will likely reveal the cause of your problem.

Solution 2

CraftBeerHipsterDude's answer helped me find the answer to the same situation I had. If AddToRole fails, the trick is to look at the result returned from Usermanager.Create(...). It might not throw an exception, but still return a results that says the creation failed. In my case it was "Username already exists".

To generalize: Check the results of earlier operations to track down the real error.

Solution 3

Answer to the question creator: The UserId should not be entered, leave that to the entity framework to create it for the users.. You are also trying to enter it as an integer, but the Id for users in role based security is a GUID in the form of a string, so it wouldn´t work anyway to try to add an integer value for a column expecting a string.

Now this wasn´t the issue for me, but I had a couple of other issues with the same error:

I tried to figure out what I was missing but found nothing wrong.

So I used another instance of VS as a debugger of the seed code(found this in another thread):

    if (System.Diagnostics.Debugger.IsAttached == false)
    System.Diagnostics.Debugger.Launch();

I noticed that the user indeed had an Id when it was being added to the role. In the end I was able to do a workaround by adding an empty catch block.. the code doesnt throw exceptions due to a false error and the users are added to the correct roles:

    try
    {
        var newUser = userManager.FindByEmail(superuserToInsert.Email);
        userManager.AddToRole(newUser.Id, "Super users");
    }
    catch 
    {
    }

Before I tried to add a newly created user to a role, the seed seemed to roll back the creation of the user and the user was never created in the user database.

But when I entirely removed the adding to role part, the user was added to the database, and on the second run of a bit edited configuration code, the user could be added to a role, leading me to think it was a a false error being thrown.. ignoring this false error with the empty catch block seems to also ignore the rollback of the user creation(which must happen behind the curtains just before the adding to role part) leading to the user existing when the adding to role part of the code.

Hope it helps someone

EDIT:

The above fixed almost all of my head ache but I noticed there were still some 300 accounts that couldn´t be created(but no errors thrown). A simple FULL OUTER JOIN and examination of the user database with the source database table lead me to think users with a dash(-) character in both the value for "UserName" and "Email" columns stopped the users from being created, and this was the case.

It was an easy fix, just configure the user manager to use more than alphanumeric characters: (and even though the attribute name seems to point to only "User Names" it also affected "Email")

    var userManager = new UserManager<ApplicationUser>(userStore);

    userManager.UserValidator = new UserValidator<ApplicationUser(userManager)
    {
        AllowOnlyAlphanumericUserNames = false,
    }; 

//Miske

Solution 4

I would avoid using the UserManager and RoleManager in your Seed method. Instead I would only use the context. Something I use is the following which creates a user and assigns him to a role:

protected override void Seed(DbModelContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException("context", "Context must not be null.");
    }

    const string UserName = "User";
    const string RoleName = "UserRole";

    var userRole = new IdentityRole { Name = RoleName, Id = Guid.NewGuid().ToString() };
    context.Roles.Add(userRole);

    var hasher = new PasswordHasher();

    var user = new IdentityUser
                   {
                       UserName = UserName,
                       PasswordHash = hasher.HashPassword(UserName),
                       Email = "[email protected]",
                       EmailConfirmed = true,
                       SecurityStamp = Guid.NewGuid().ToString()
                   };

    user.Roles.Add(new IdentityUserRole { RoleId = userRole.Id, UserId = user.Id });

    context.Users.Add(user);

    base.Seed(context);
}

The Entity classes are custom implementations (because I wanted to use GUIDs as the IDs), but they derive from the framework classes. With that it should work in the same way if you change them to the appropriate framework classes.

EDIT

I removed the custom classes and switched them to the framework classes, because there were some confusion.

Share:
19,153

Related videos on Youtube

Analytic Lunatic
Author by

Analytic Lunatic

Software Developer by Day, Web Designer by Night.

Updated on June 06, 2022

Comments

  • Analytic Lunatic
    Analytic Lunatic almost 2 years

    I have been experimenting with MVC5/EF6 and trying out the new Identity Authentication with Code-First Migrations. Everything in the solution is currently building and I can add a Migration, but when I perform an update-database through the package manager console in VS2013, my Configuration.cs file fails to fully process my test data into my Tables and outputs Error Adding User to Role: UserId not found.

    I have tried explicitly setting a User ID and leaving it to be generated by the Manager (as seen in some examples), but each time I receive the same error message. I know the error is failing in my #region User & User Roles of my Configuration.cs file, but I'm not sure why:

    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using PersonalPortfolio2.Helper;
    using PersonalPortfolio2.Models;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Diagnostics;
    using System.Linq;
    
    namespace PersonalPortfolio2.Models
    {
        public sealed class Configuration : DbMigrationsConfiguration<PersonalPortfolio2.Models.ApplicationDbContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(PersonalPortfolio2.Models.ApplicationDbContext context)
            {
                BlobHelper bh = new BlobHelper();
                //LocationHelper lh = new LocationHelper();
                ApplicationDbContext db = new ApplicationDbContext();
    
                #region Roles
                try
                {
                    List<string> myRoles = new List<string>(new string[] { "Root", "Admin", "Outsider", "Client", "Primary" });
                    var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
    
                    foreach (string r in myRoles)
                    {
                        RoleManager.Create(new IdentityRole(r));
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error Create Roles: " + ex.Message);
                }
                #endregion
    
                #region User & User Roles
                var store = new UserStore<ApplicationUser>(context);
                var manager = new UserManager<ApplicationUser>(store);
    
                List<ApplicationUser> myUsers = GetTestUsers();
                var passwordHasher = new PasswordHasher();
    
                foreach (var u in myUsers)
                {
                    var userExists = db.Users.Where(a => a.Email == u.Email).FirstOrDefault();
                    if (userExists == null)
                    {
                        var user = new ApplicationUser
                        {
                            Email = u.Email,
                            PasswordHash = passwordHasher.HashPassword("P@ssword1"),
                            LockoutEnabled = false,
                            Name = u.Name,
                            Position = u.Position,
                            RegisteredDate = DateTime.Now,
                            LastVisitDate = DateTime.Now,
                            OrganizationId = u.OrganizationId,
                            ProfilePictureSrc = u.ProfilePictureSrc,
                        };
    
                        try
                        {
                            var userCreateResult = manager.Create(user);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Error Add User: " + ex.Message + "\n" + ex.InnerException);
                        }
    
                        // Add User to Roles
                        List<string> usersRoles = GetUserRoles(u.Email);
                        bool codeHit = false;
                        foreach (string role in usersRoles)
                        {
                            try
                            {
                                codeHit = true;
                                manager.AddToRole(user.Id, role);
                            }
                            catch (Exception ex)
                            {
                                // ERROR!
                                throw new Exception("Error Adding User to Role: " + ex.Message + "\n" + ex.Data + "\n" + ex.InnerException + "\nName: " + user.Name + "\nEmail: " + user.Email + "\nuser.ID: " + user.Id + "\nu.Id: " + u.Id + "\nRole: " + role + "\nCodeHit: " + codeHit);
                            }
                        }
                    }
    
                }
                #endregion
    
    }
    
                #region Helpers
                private List<ApplicationUser> GetTestUsers()
                {
                    List<ApplicationUser> testUsers = new List<ApplicationUser>
                    {
                        new ApplicationUser
                        {
                            Id = "1",
                            Email = "[email protected]",
                            Name = "Admin User",
                            RegisteredDate = System.DateTime.Now,
                            LastVisitDate = System.DateTime.Now,
                            Position = "Site Administrator",
                            PhoneNumber = "1234564321",
                        },
                        new ApplicationUser
                        {
                            Id = "2",
                            Email = "[email protected]",
                            Name = "James Woods",
                            RegisteredDate = System.DateTime.Now,
                            LastVisitDate = System.DateTime.Now,
                            Position = "Software Developer / Web Designer",
                            PhoneNumber = "1234567890",
                        },
                        new ApplicationUser
                        {
                            Id = "3",
                            Email = "[email protected]",
                            Name = "Tyler Perry",
                            RegisteredDate = System.DateTime.Now,
                            LastVisitDate = System.DateTime.Now,
                            Position = "Company Contact",
                            PhoneNumber = "1234567890",
                        }
                    };
                    return testUsers;
                }
    
    
                public List<string> GetUserRoles(string user)
                {
                    List<string> myRoles = new List<string>();
                    switch (user)
                    {
                            //"Root", "Admin", "Outsider", "Client", "Primary"
                        case "[email protected]":
                            myRoles = new List<string>(new string[] { "Root", "Admin" });
                            break;
                        case "[email protected]":
                            myRoles = new List<string>(new string[] { "Admin" });
                            break;
                        case "[email protected]":
                            myRoles = new List<string>(new string[] { "Client", "Outsider" });
                            break;
                        default:
                            myRoles = new List<string>(new string[] {"[user] not found."});
                            break;
                    }
                    return myRoles;
                }
                #endregion
    
        }
    }
    

    Can anyone offer some insight here with what I may be overlooking? For full details, my current catch statment is outputting the following:

    Error Adding User to Role: UserId not found.
    System.Collections.ListDictionaryInternal
    
    Name: Admin User
    Email: [email protected]
    user.ID: 1
    u.Id: 1
    Role: Root
    CodeHit: True
    

    When I comment out the explicit Id = "1", for my Admin User, the user.ID and u.Id becomes: ab753316-3d7b-4f98-a13a-d19f7c926976. I had thought it might be my helper methods of GetTestUsers() or GetUserRoles(u.Email) which were the issue, but between my try/catch and the codeHit boolean variable I am using, I have verified the issue is definitely coming from manager.AddToRole(user.Id, role).

    • CShark
      CShark over 6 years
      Were you able to solve your issue?
  • Analytic Lunatic
    Analytic Lunatic almost 10 years
    Thanks for replying Horizon. I believe we are on different levels of experience here, and I'm having difficulty implementing a similar solution to what you have suggested with your custom classes.
  • Horizon_Net
    Horizon_Net almost 10 years
    @AnalyticLunatic The custom classes are irrelevant for this sample. They are just a layer above the framework implementation. To avoid confusion I updated my sample to the framework classes. Like you see it is only a switch in the names of the classes. Remember that you maybe have to change the IDs from GUIDs to strings (just adding ToString()) depending on what you're using as the data type for your IDs.
  • Analytic Lunatic
    Analytic Lunatic almost 10 years
    So, should I scrap my current method I am attempting? When my current code fails out, my [AspNetRoles] table has all of my roles, but while var userCreateResult = manager.Create(user); processes, neither the AspNetUsers nor AspNetUserRoles has even one entry.
  • Analytic Lunatic
    Analytic Lunatic almost 10 years
    Hey Horizon, I figured it out, but maybe you could offer some insight? When I compared my example application, I finally found what I had done different. The example was initializing all my new ApplicationUser with UserName = u.Email, which I took to be a UserName field I did not need in my application. When I hover over the field, it says string IdentityUser<string,IdentityUserLogin,IdentityUserRole,Ident‌​ityUserClaim>.UserNa‌​me. Any thoughts as to why setting Username = u.Email fixed my issue of UserId not found?
  • CShark
    CShark over 8 years
    @AnalyticLunatic It's not quite clear what you did. Can you please update your question with the new code? I am struggling with the same issue.
  • Analytic Lunatic
    Analytic Lunatic over 8 years
    @CraftBeerHipsterDude It's been awhile, but from what I recall the issue I was having at the time was solved by me using the above code I initially posted, with the ADDITION of specifying UserName = u.Email within each of my new ApplicationUser { ... } definitions. Hope it helps!
  • Analytic Lunatic
    Analytic Lunatic over 8 years
    Glad to hear you were able to get it figured out!
  • Rudey
    Rudey about 8 years
    Is strange how Create still assigns a new ID to user even though there are hidden errors. My mistake was "Name can not be empty"...
  • Has AlTaiar
    Has AlTaiar about 8 years
    Thanks @CraftBeerHipsterDude, your answer is spot on. But sometimes you could get a different error (duplicate user email, etc) and it would be hiding behind the same error message. See Ted's answer below
  • Ryan Taite
    Ryan Taite over 6 years
    Thank you, Ted! I was trying to seed a new user in Configuration.cs so I wasn't able to put a working breakpoint on it until I moved the code into a controller that I could activate and a result variable like so: var result = await userManager.CreateAsync(user, "somePassword");. Had an invalid email address of all things! "Can only contain numbers or letters"