简体   繁体   中英

How can I link a user to another user in ASP.NET MVC 5 and Identity (Entity Framework Code-First)

I need help linking a user to another user in ASP.NET MVC 5 and ASP.NET Identity in Entity Framework Code-First approach.

The use case here is when I create a user I need to choose a user in the ReportsTo dropdown list which shows the user's first and last name and saves the selected user's ID in my ReportsTo column in the Identity User table. This list of users needs to be a list of the existing Identity users in the database.

I have implemented bits of various topics and managed to get a drop down list to display with the Identity users in my user create and edit views. It saves the ID in my ReportsTo column in the database, but when I edit the user the ReportsTo field does not keep the ID saved in the database unless I make the same selection in the dropdown list again (it overwrites the previously saved value with a blank if I don't make a selection again as it doesn't load the previosuly saved value in the edit view), and on the details page and in my user list table it displays the ReportsTo saved user as a GUID.

In my User Controller:

public UserController()
        {
            using (var userList = new ApplicationDbContext())
            {
                ViewBag.ReportsTo = userList.Users.Select(user => new SelectListItem { Text = user.FirstName + " " + user.LastName, Value = user.Id }).ToList();
            }
        } 

public ActionResult Create()
        {
            // Show a list of available groups:
            ViewBag.GroupsList =
                new SelectList(this.GroupManager.Groups, "Id", "Name");
            return View();
        } 

[HttpPost]
        public async Task<ActionResult> Create(RegisterViewModel userViewModel, params string[] selectedGroups)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser
                {
                    UserName = userViewModel.Email,
                    FirstName = userViewModel.FirstName,
                    LastName = userViewModel.LastName,
                    ReportsTo = userViewModel.ReportsTo,
                    OfficeNumber = userViewModel.OfficeNumber,
                    CellNumber = userViewModel.CellNumber,
                    Email = userViewModel.Email
                };
                var adminresult = await UserManager
                    .CreateAsync(user, userViewModel.Password);

                //Add User to the selected Groups 
                if (adminresult.Succeeded)
                {
                    if (selectedGroups != null)
                    {
                        selectedGroups = selectedGroups ?? new string[] { };
                        await this.GroupManager
                            .SetUserGroupsAsync(user.Id, selectedGroups);
                    }
                    return RedirectToAction("Users");
                }
            }
            ViewBag.Groups = new SelectList(
                await RoleManager.Roles.ToListAsync(), "Id", "Name");
            return View();
        } 

public async Task<ActionResult> Edit(string id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var user = await UserManager.FindByIdAsync(id);
            if (user == null)
            {
                return HttpNotFound();
            }

            // Display a list of available Groups:
            var allGroups = this.GroupManager.Groups;
            var userGroups = await this.GroupManager.GetUserGroupsAsync(id);

            var model = new EditUserViewModel()
            {
                Id = user.Id,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                ReportsTo = user.ReportsTo,
                OfficeNumber = user.OfficeNumber,
                CellNumber = user.CellNumber
            };

            foreach (var group in allGroups)
            {
                var listItem = new SelectListItem()
                {
                    Text = group.Name,
                    Value = group.Id,
                    Selected = userGroups.Any(g => g.Id == group.Id)
                };
                model.GroupsList.Add(listItem);
            }
            return View(model);
        } 

[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Edit(
            [Bind(Include = "Email,Id,FirstName,LastName,ReportsTo,OfficeNumber,CellNumber")] EditUserViewModel editUser,
            params string[] selectedGroups)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindByIdAsync(editUser.Id);
                if (user == null)
                {
                    return HttpNotFound();
                }

                // Update the User:
                user.UserName = editUser.Email;
                user.Email = editUser.Email;
                user.FirstName = editUser.FirstName;
                user.LastName = editUser.LastName;
                user.ReportsTo = editUser.ReportsTo;
                user.OfficeNumber = editUser.OfficeNumber;
                user.CellNumber = editUser.CellNumber;
                await this.UserManager.UpdateAsync(user);

                // Update the Groups:
                selectedGroups = selectedGroups ?? new string[] { };
                await this.GroupManager.SetUserGroupsAsync(user.Id, selectedGroups);
                return RedirectToAction("Users");
            }
            ModelState.AddModelError("", "Something failed.");
            return View();
        } 

My EditUserViewModel:

public class EditUserViewModel
    {
        public EditUserViewModel()
        {
            this.RolesList = new List<SelectListItem>();
            this.GroupsList = new List<SelectListItem>();
        }
        public string Id { get; set; }

        [Required(AllowEmptyStrings = false)]
        [Display(Name = "Email")]
        [EmailAddress]
        public string Email { get; set; }
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Reports To")]
        public string ReportsTo { get; set; }

        [Display(Name = "Office Number")]
        public string OfficeNumber { get; set; }

        [Display(Name = "Cell Number")]
        public string CellNumber { get; set; }

        [Display(Name = "ProfilePicture")]
        public byte[] ProfilePicture { get; set; }

        public ICollection<SelectListItem> RolesList { get; set; }

        public ICollection<SelectListItem> GroupsList { get; set; }
    } 

The dropdown list in my create and edit views

@Html.DropDownList("ReportsTo", ViewBag.Users as SelectList, "Choose User", htmlAttributes: new { @class = "form-control" }) 

I need to get the dropdown list to retrieve the currently saved value in my edit view and to display the GUID in my index and details views as the user's First and Last name. If anyone has an alternative solution instead of trying to accomplish it with the current method I would be happy to try that too.

Thanks in advance :)

I have managed to get around the issue. It might not be the absolute best solution but it seems to work. Here is the solution below. I have replaced ReportsTo from the code above with SuperiorID in the solution. Note that my Identity Users have integers for their ID's and not GUID's like the default Identity implementation.

With the below code I have linked an Identity User to another Identity User.

In my Identity Models I have the following in my ApplicationUser : Identity User class:

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int? SuperiorID { get; set; }
        public string FullName
        {
            get
            {
                return FirstName + " " + LastName;
            }
        } 

        public async Task<ClaimsIdentity>
            GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
        {
            var userIdentity = await manager
                .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            return userIdentity;
        }

        public virtual ApplicationUser Superior { get; set; }

    } 

I created an abstract for Superiors that inherits the Identity User so that I can get the User's ID and Full Name which I also placed in my Identity Models:

public abstract class Superior : IdentityUser
    {

    } 

I added the following in my RegisterViewModel so that I can add a Superior on user creation:

public class RegisterViewModel
    {
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        public string FullName
        {
            get
            {
                return FirstName + " " + LastName;
            }
        }

        [Display(Name = "Superior")]

        public virtual ApplicationUser Superior { get; set; }

    } 

I added the following in my EditUserViewModel so that I can edit the user's Superior in my edit view:

public class EditUserViewModel
    {
        public int Id { get; set; }

        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        public string FullName
        {
            get
            {
                return FirstName + " " + LastName;
            }
        }

        [Display(Name = "Superior")]
        public int? SuperiorID { get; set; }

        public virtual ApplicationUser Superior { get; set; }

    } 

Here is the code for the UserController. I removed code not related to this and left some code to give an indication where the code needs to go:

This goes in the main class:

private ApplicationDbContext db = new ApplicationDbContext(); 


public async Task<ActionResult> Index(int? SelectedSuperior)
        {
            var superiors = db.Users.OrderBy(s => s.FirstName).ToList();
            ViewBag.SelectedSuperior = new SelectList(superiors, "Id", "FullName", SelectedSuperior);
            int superiorID = SelectedSuperior.GetValueOrDefault();

            IQueryable<ApplicationUser> users = db.Users
                .Where(c => !SelectedSuperior.HasValue || c.SuperiorID == superiorID)
                .OrderBy(d => d.Id)
                .Include(d => d.Superior);
            var sql = users.ToString();

            return View(await UserManager.Users.ToListAsync());
        } 

public ActionResult Create()
        {
            PopulateSuperiorsDropDownList();
            return View();
        } 

public async Task<ActionResult> Create(RegisterViewModel userViewModel)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser
                {
                    FirstName = userViewModel.FirstName,
                    LastName = userViewModel.LastName,
                    SuperiorID = userViewModel.SuperiorID,
                };

            }
            PopulateSuperiorsDropDownList(userViewModel.SuperiorID);
            return View();
        } 

public async Task<ActionResult> Edit(int id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var user = await UserManager.FindByIdAsync(id);
            if (user == null)
            {
                return HttpNotFound();
            }

            var model = new EditUserViewModel()
            {
                Id = user.Id,
                FirstName = user.FirstName,
                LastName = user.LastName,
                SuperiorID = user.SuperiorID,
            };
            PopulateSuperiorsDropDownList(user.SuperiorID);
            return View(model);
        } 

public async Task<ActionResult> Edit([Bind(Include = "Email,Id,FirstName,LastName,SuperiorID")] EditUserViewModel editUser)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindByIdAsync(editUser.Id);
                if (user == null)
                {
                    return HttpNotFound();
                }

                // Update the User:
                user.Email = editUser.Email;
                user.FirstName = editUser.FirstName;
                user.LastName = editUser.LastName;
                user.SuperiorID = editUser.SuperiorID;
            }
            ModelState.AddModelError("", "Something failed.");
            PopulateSuperiorsDropDownList(editUser.SuperiorID);
            return View();
        } 

private void PopulateSuperiorsDropDownList(object selectedSuperior = null)
        {
            var superiorsQuery = from s in db.Users
                                   orderby s.FirstName + " " + s.LastName
                                   select s;
            ViewBag.SuperiorID = new SelectList(superiorsQuery, "Id", "FullName", selectedSuperior);
        } 

Here is the dropdown list for the create and edit view so that a Superior can be assigned to a user:

@Html.DropDownList("SuperiorID", null, "Choose Superior", htmlAttributes: new { @class = "form-control" }) 

To show the Full Name of the user's Superior in the details page I use the below code:

@Html.TextBoxFor(m => m.Superior.FullName, new { @class = "form-control", @disabled = "disabled" }) 

To show the Full Name of the user's Superior in my datatable on my index page I used the below method:

<table class="table" id="users-table" width="100%">
                    <thead>
                        <tr>
                            <th title="First Name">
                                First Name
                            </th>
                            <th title="Last Name">
                                Last Name
                            </th>
                            <th title="Superior">
                                Superior
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var item in Model)
                        {
                            <tr>
                                <td>
                                    @Html.DisplayFor(modelItem => item.FirstName)
                                </td>
                                <td>
                                    @Html.DisplayFor(modelItem => item.LastName)
                                </td>
                                <td>
                                    @Html.DisplayFor(modelItem => item.Superior.FullName)
                                </td>
                            </tr>
                        }
                    </tbody>
</table> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM