The following code is giving me headaches. As you can see, I have a pretty standard AccountController with a "Register" method. Upon registration, the user should be given the role " Module_All__Admin ". The code seems correct and "resultAssigningRole.Succeeded" returns true... why is then my "AspNetUserRoles" table in the SQL database empty?

Note: the connection string works fine, in a separated controller I filled the "AspNetRoles" table and it worked.

public class AccountController : Controller
    {
        private readonly UserManager<IdentityUser> _userManager;
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly RoleManager<IdentityRole> _roleManager;
        private readonly ILogger _logger;
        private readonly IEmailSender _emailSender;

        public AccountController(
            UserManager<IdentityUser> userManager,
            SignInManager<IdentityUser> signInManager,
            RoleManager<IdentityRole> roleManager,
            ILoggerFactory loggerFactory,
            IEmailSender emailSender
            )
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _roleManager = roleManager;
            _logger = loggerFactory.CreateLogger<AccountController>();
            _emailSender = emailSender;
        }

public async Task<IActionResult> Register(LoginViewModel loginViewModel)
        {
            if (ModelState.IsValid)
            {
                IdentityUser user = new IdentityUser() { UserName = loginViewModel.Email };
                IdentityResult resultCreatingUser = await _userManager.CreateAsync(user, loginViewModel.Password);
                if (resultCreatingUser.Succeeded) //this returns true
                {
                    if (await _roleManager.RoleExistsAsync("Module_All__Admin"))
                    {
                        IdentityResult resultAssigningRole = await _userManager.AddToRoleAsync(user, "Module_All__Admin");
                        if (resultAssigningRole.Succeeded) //this returns true
                        {
                            await _signInManager.SignInAsync(user, isPersistent: false);
                            _logger.LogInformation(3, "User created, assigned to role 'AllModules - User'");
                        }
                        else
                        {
                            var errors = resultAssigningRole.Errors;
                            var message = string.Join(", ", errors);
                            ModelState.AddModelError("", message);
                        }

                    }
                    return RedirectToAction("LoggedIn", "Account");
                }
            }
            return View("~/Views/Home/Index.cshtml");
        }

    }

EDIT Everybody, it seems to be an bug in ASP.NET CORE. I found in github that ensuring your services are set like this solves the situation:

        services.AddIdentity<IdentityUser, IdentityRole>()
                   .AddEntityFrameworkStores<ApplicationDbContext>()
                   .AddDefaultUI()
                   .AddDefaultTokenProviders();

It worked for me.

1 Answers

0
scgough On

After you call _userManager.CreateAsync(... does your user object have an Id?

If not, try this. It will go off and get the new user from the db via username (or email if you prefer) and use the Id from that to assign the role.

            ...
            if (resultCreatingUser.Succeeded) //this returns true
            {
                if (await _roleManager.RoleExistsAsync("Module_All__Admin"))
                {
                    //Retrieve the user from the database by userName (or Email if unique)
                    var _newUser = await _userManager.FindByNameAsync(user.userName)

                    IdentityResult resultAssigningRole = await _userManager.AddToRoleAsync(_newUser, "Module_All__Admin");
                    if (resultAssigningRole.Succeeded) //this returns true
                    {
                        ...