Search code examples
c#asp.net-mvcregistrationaccountrole

Setting AspNetUserRoles when Registering users


Here's what I want to do: I want to set the AspNetUserRole to the new user, right in the Registration page.

Model:

    namespace MyProject.Models
    {
        public enum AccountRole
        {
            Responder = 10003, Sender= 10002, Admin = 10001
        }

        ...

        [Required()]
        [Display(Name = "Account role")]
        public AccountRole? AccountRole { get; set; }

View:

@Html.LabelFor(model => model.AccountRole, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EnumDropDownListFor(model => model.AccountRole, htmlAttributes: new { @class = "form-control" })
            @Html.ValidationMessageFor(model => model.AccountRole, "", new { @class = "text-danger" })
        </div>

Registration page result: https://i.sstatic.net/lEokn.jpg

Controller:

    // POST: /Account/Register
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
            IdentityResult result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                //User accountRole to AspNetUserRoles BY JULIUS
                var accountRole = model.AccountRole;

                await SignInAsync(user, isPersistent: false);

                string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                var callbackUrl = Url.Action("ConfirmEmail", "Account",
                   new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                await UserManager.SendEmailAsync(user.Id,
                   "Confirm your account", "Please confirm your account by clicking <a href=\""
                   + callbackUrl + "\">here</a>");


                return RedirectToAction("Index", "Home");
            }
            else
            {
                AddErrors(result);
            }
        }

Please direct your attention to the AccountController.cs Register part. I have successfully collected the entered the AccountRole Enum from the dropdown:

var accountRole = model.AccountRole;

What I want to do is set accountRole to the AspNetUserRoles table in my Entity Framework generated DefaultConnection

Table: https://i.sstatic.net/QMEQ2.png

How do I solve this in my Controller code?


Solution

  • From what I understand you may want to extend the IdentityUserRole class. This class represents the relation between a user and his role.

    public class AccountRole: IdentityUserRole<TKey>
    {
        public override TKey RoleId
        {
            get;
            set;
        }
        public override TKey UserId
        {
            get;
            set;
        }
        public IdentityUserRole()
        {
        }
    
        public string somenewproperty(){
            get; set;
        }
    }
    

    Then I believe you will have to override your createUserRole in the userManager or more specific the RoleManager

    public class ApplicationRoleManager : RoleManager<IdentityRole> {
     //...And so on
    }
    

    Check out this link for a full overview of the identity management

    What I don't really get is why you would want to do this in the first place. You could add a new role to the Roles table and tie that role to certain rules and in that case you could just use the built-in RoleManager to assign roles to users.

    await userManager.AddToRoleAsync(userId, AccountRole.Admin);

    and in this case, your AccountRole will be an Enum

    public enum AccountRole {
        Admin,
        User
    }
    

    So to make this work, you will have to add the roles to the database like so:

     context.Roles.Add(new IdentityRole("SomeRoleNameHere"));
    

    this is best done in the Seed method;

    Then you have your register method:

    [Route("Register")]
    public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {
        //Do the register of the user
        //Next:
        await UserManager.AddToRoleAsync(userId, AccountRole.Admin);
    }
    

    This will add the user to the role of "Admin" if added correctly. Now if you look in the database, the AspNetUserRoles will have your UserId and RoleId matched to one another.

    If you cannot get this to work, you can also make a static class, I did this in a previous project. It works the same way only the "rolenames" object looks like this:

    public static class RoleNames {
        public const string Supervisor = "Supervisor";
        public const string Administrator = "Administrator";
    }
    

    All the other things - like adding them to the DB in the seed method and so on are exactly the same. And adding it to a user as well:

    await userManager.AddToRoleAsync(UserId, RoleNames.Supervisor);