0

I am trying to save a multi select list on my user create in MVC 5, but the values are not saving. Values are saving only in edit. For some reason it's not working on create and it seems the issue is tied to the identity user. I have the same method implemented in a different controller for another entity and it's working fine.

I am trying to assign multiple health professionals to a user in the below code. I am not getting any errors or a break on save, it just doesn't save the values.

Can anyone please have a look at my code and give me a solution to this problem.

Here is my controller code relevant to creating a user:

public ActionResult Create()
        {
            PopulateDepartmentsDropDownList();
            PopulateSuperiorsDropDownList();
            // Show a list of available groups:
            ViewBag.GroupsList = new SelectList(this.GroupManager.Groups, "Id", "Name");
            var applicationUser = new ApplicationUser();
            applicationUser.HealthProfessionals = new List<HealthProfessional>();
            PopulateAssignedHealthProfessionals(applicationUser);
            return View();
        }


        [HttpPost]
        public async Task<ActionResult> Create([Bind(Exclude = "ProfilePicture")]RegisterViewModel userViewModel, ApplicationUser applicationUser, string[] selectedHealthProfessionals, params string[] selectedGroups)
        {
            if (selectedHealthProfessionals != null)
            {
                applicationUser.HealthProfessionals = new List<HealthProfessional>();
                foreach (var healthProfessional in selectedHealthProfessionals)
                {
                    var healthProfessionalToAdd = db.HealthProfessionals.Find(int.Parse(healthProfessional));
                    applicationUser.HealthProfessionals.Add(healthProfessionalToAdd);
                }
            }
            if (ModelState.IsValid)
            {
                // To convert the user uploaded Photo as Byte Array before save to DB
                byte[] imageData = null;
                if (Request.Files.Count > 0)
                {
                    HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];

                    using (var binary = new BinaryReader(poImgFile.InputStream))
                    {
                        imageData = binary.ReadBytes(poImgFile.ContentLength);
                    }
                }

                var user = new ApplicationUser
                {
                    UserName = userViewModel.Email,
                    FirstName = userViewModel.FirstName,
                    LastName = userViewModel.LastName,
                    Position = userViewModel.Position,
                    DepartmentID = userViewModel.DepartmentID,
                    SuperiorID = userViewModel.SuperiorID,
                    OfficeNumber = userViewModel.OfficeNumber,
                    CellNumber = userViewModel.CellNumber,
                    Email = userViewModel.Email
                };

                //Here we pass the byte array to user context to store in db
                user.ProfilePicture = imageData;

                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");
            PopulateDepartmentsDropDownList(userViewModel.DepartmentID);
            PopulateSuperiorsDropDownList(userViewModel.SuperiorID);
            PopulateAssignedHealthProfessionals(applicationUser);
            return View(applicationUser);
        }

private void PopulateAssignedHealthProfessionals(ApplicationUser applicationUser)
        {
            var allHealthProfessionals = db.HealthProfessionals;
            var userHealthProfessionals = new HashSet<int>(applicationUser.HealthProfessionals.Select(i => i.HealthProfessionalID));
            var viewModel = new List<AssignedHealthProfessionals>();
            foreach (var healthProfessional in allHealthProfessionals)
            {
                viewModel.Add(new AssignedHealthProfessionals
                {
                    HealthProfessionalID = healthProfessional.HealthProfessionalID,
                    HealthProfessionalName = healthProfessional.Name,
                    HealthProfessionalSurname = healthProfessional.Surname,
                    Assigned = userHealthProfessionals.Contains(healthProfessional.HealthProfessionalID)
                });
            }
            ViewBag.HealthProfessionals = viewModel;
        } 

Here is my create view:

@model MyApp.Models.RegisterViewModel

@{
    ViewBag.Title = "Create User";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<link href="@Url.Content("~/Content/CSS/dropify.min.css")" rel="stylesheet" type="text/css" />

<div class="m-grid__item m-grid__item--fluid m-wrapper">
    <div class="m-subheader ">
        <div class="d-flex align-items-center">
            <div class="mr-auto">
                <h3 class="m-subheader__title m-subheader__title--separator">
                    Add User
                </h3>
                <ul class="m-subheader__breadcrumbs m-nav m-nav--inline">
                    <li class="m-nav__item m-nav__item--home">
                        <a href="@Url.Action("Dashboard","Home")" class="m-nav__link m-nav__link--icon">
                            <i class="m-nav__link-icon la la-home"></i>
                        </a>
                    </li>
                    <li class="m-nav__separator">
                        -
                    </li>
                    <li class="m-nav__item">
                        <a href="@Url.Action("Users","UserManagement")" class="m-nav__link">
                            <span class="m-nav__link-text">
                                Users
                            </span>
                        </a>
                    </li>
                </ul>
            </div>
            <div>
            </div>
        </div>
    </div>

    @using (Html.BeginForm("Create", "UserManagement", FormMethod.Post, new { @class = "m-form m-form--fit m-form--label-align-right", role = "form", enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()
        <div class="m-content">

            <div class="m-portlet m-portlet--mobile">
                <div class="m-portlet__head">
                    <div class="m-portlet__head-caption">
                        <div class="m-portlet__head-title">
                            <h3 class="m-portlet__head-text">
                                User Details
                            </h3>
                        </div>
                    </div>
                </div>

                <div class="m-portlet__body">
                    <div class="m-form__section m-form__section--first">
                        <div class="row">
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        Email Address
                                    </label>
                                    @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        First Name
                                    </label>
                                    @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.FirstName, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        Last Name
                                    </label>
                                    @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.LastName, "", new { @class = "text-danger" })
                                </div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        Position
                                    </label>
                                    @Html.TextBoxFor(m => m.Position, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.Position, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        Department
                                    </label>
                                    @Html.DropDownList("DepartmentID", null, "Choose Department", htmlAttributes: new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.DepartmentID, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-4">
                                <div class="form-group">
                                    <label>
                                        Superior
                                    </label>
                                    @Html.DropDownList("SuperiorID", null, "Choose Superior", htmlAttributes: new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.SuperiorID, "", new { @class = "text-danger" })
                                </div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        Password
                                    </label>
                                    @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        Confirm Password
                                    </label>
                                    @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.ConfirmPassword, "", new { @class = "text-danger" })
                                </div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        Office Number
                                    </label>
                                    @Html.TextBoxFor(m => m.OfficeNumber, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.OfficeNumber, "", new { @class = "text-danger" })
                                </div>
                            </div>
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        Cell Number
                                    </label>
                                    @Html.TextBoxFor(m => m.CellNumber, new { @class = "form-control" })
                                    @Html.ValidationMessageFor(m => m.CellNumber, "", new { @class = "text-danger" })
                                </div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        User Groups
                                    </label>
                                    <div class="m-checkbox-list">
                                        @foreach (var item in (SelectList)ViewBag.GroupsList)
                                        {
                                            <label class="m-checkbox m-checkbox--success">
                                                <input type="checkbox" name="selectedGroups" value="@item.Value">
                                                @Html.Label(item.Text, new { @class = "control-label" })
                                                <span></span>
                                            </label>
                                        }
                                    </div>
                                </div>
                            </div>
                            <div class="col-lg-6">
                                <div class="form-group">
                                    <label>
                                        Health Professionals
                                    </label>
                                    <div class="m-checkbox-list">
                                        @{
                                            int cnt = 0;
                                            List<MyApp.ViewModels.AssignedHealthProfessionals> healthProfessionals = ViewBag.HealthProfessionals;
                                            foreach (var healthProfessional in healthProfessionals)
                                            {
                                                if (cnt++ % 3 == 0)
                                                {

                                                }
                                                <label class="m-checkbox m-checkbox--success">
                                                    <input type="checkbox" name="selectedHealthProfessionals" value="@healthProfessional.HealthProfessionalID" @(Html.Raw(healthProfessional.Assigned ? "checked=\"checked\"" : ""))>
                                                    @Html.Label(healthProfessional.HealthProfessionalName, new { @class = "control-label" }) @Html.Label(healthProfessional.HealthProfessionalSurname, new { @class = "control-label" })
                                                    <span></span>
                                                </label>
                                            }
                                        }
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-lg-12">
                                <div class="form-group">
                                    <label>
                                        Profile Picture
                                    </label>
                                    <input type="file" name="UserPhoto" id="fileUpload" accept=".png,.jpg,.jpeg,.gif,.tif" class="dropify" />
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

            </div>

            <div class="m-portlet__body">

                <!-- Form Actions Start -->

                <div class="m-portlet">

                    <div class="m-portlet__head">
                        <div class="m-portlet__head-caption">
                            <div class="m-portlet__head-title">
                                <h3 class="m-portlet__head-text">
                                    Actions
                                </h3>
                            </div>
                        </div>
                    </div>
                    <div class="m-portlet__foot m-portlet__foot--fit">
                        <div class="m-form__actions">
                            <input type="submit" class="btn btn-accent m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill" value="Save" />
                            @Html.ActionLink("Cancel", "Users", null, new { @class = "btn m-btn--pill m-btn--air btn-brand m-btn m-btn--custom" })
                        </div>
                    </div>

                </div>

                <!-- Form Actions End -->

            </div>

        </div>

    }

</div>

<script src="@Url.Content("~/Scripts/jquery.min.js")"></script>
<script src="@Url.Content("~/Scripts/dropify.min.js")"></script>

<script>
    $(document).ready(function () {
        // Basic
        $('.dropify').dropify();

        // Translated
        $('.dropify-fr').dropify({
            messages: {
                default: 'Glissez-déposez un fichier ici ou cliquez',
                replace: 'Glissez-déposez un fichier ou cliquez pour remplacer',
                remove: 'Supprimer',
                error: 'Désolé, le fichier trop volumineux'
            }
        });

        // Used events
        var drEvent = $('#input-file-events').dropify();

        drEvent.on('dropify.beforeClear', function (event, element) {
            return confirm("Do you really want to delete \"" + element.file.name + "\" ?");
        });

        drEvent.on('dropify.afterClear', function (event, element) {
            alert('File deleted');
        });

        drEvent.on('dropify.errors', function (event, element) {
            console.log('Has Errors');
        });

        var drDestroy = $('#input-file-to-destroy').dropify();
        drDestroy = drDestroy.data('dropify')
        $('#toggleDropify').on('click', function (e) {
            e.preventDefault();
            if (drDestroy.isDropified()) {
                drDestroy.destroy();
            } else {
                drDestroy.init();
            }
        })
    });
</script> 

Here is the controller for the edit function which works:

public async Task<ActionResult> Edit(int id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            ApplicationUser applicationUser = db.Users.Include(h => h.HealthProfessionals).Where(h => h.Id == id).Single();
            PopulateAssignedHealthProfessionals(applicationUser);
            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,
                Position = user.Position,
                DepartmentID = user.DepartmentID,
                SuperiorID = user.SuperiorID,
                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);
            }
            PopulateDepartmentsDropDownList(user.DepartmentID);
            PopulateSuperiorsDropDownList(user.SuperiorID);
            return View(model);
        }

        private void PopulateAssignedHealthProfessionals(ApplicationUser applicationUser)
        {
            var allHealthProfessionals = db.HealthProfessionals;
            var userHealthProfessionals = new HashSet<int>(applicationUser.HealthProfessionals.Select(i => i.HealthProfessionalID));
            var viewModel = new List<AssignedHealthProfessionals>();
            foreach (var healthProfessional in allHealthProfessionals)
            {
                viewModel.Add(new AssignedHealthProfessionals
                {
                    HealthProfessionalID = healthProfessional.HealthProfessionalID,
                    HealthProfessionalName = healthProfessional.Name,
                    HealthProfessionalSurname = healthProfessional.Surname,
                    Assigned = userHealthProfessionals.Contains(healthProfessional.HealthProfessionalID)
                });
            }
            ViewBag.HealthProfessionals = viewModel;
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Edit([Bind(Include = "Email,Id,FirstName,LastName,Position,DepartmentID,SuperiorID,OfficeNumber,CellNumber", Exclude = "ProfilePicture")] EditUserViewModel editUser, ApplicationUser applicationUser, int? id, string[] selectedHealthProfessionals, params string[] selectedGroups)
        {
            if (ModelState.IsValid)
            {
                // To convert the user uploaded Photo as Byte Array before save to DB
                byte[] imageData = null;
                if (Request.Files.Count > 0)
                {
                    HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];

                    using (var binary = new BinaryReader(poImgFile.InputStream))
                    {
                        imageData = binary.ReadBytes(poImgFile.ContentLength);
                    }
                }

                var user = await UserManager.FindByIdAsync(editUser.Id);
                if (user == null)
                {
                    return HttpNotFound();
                }

                var applicationUserToUpdate = db.Users.Include(h => h.HealthProfessionals).Where(h => h.Id == id).Single();

                if (TryUpdateModel(applicationUserToUpdate, "",
               new string[] { }))
                {
                    try
                    {
                        UpdateUserHealthProfessionals(selectedHealthProfessionals, applicationUserToUpdate);

                        db.SaveChanges();

                        return RedirectToAction("Users");
                    }
                    catch (RetryLimitExceededException /* dex */)
                    {
                        //Log the error (uncomment dex variable name and add a line here to write a log.
                        ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
                    }
                }
                PopulateAssignedHealthProfessionals(applicationUserToUpdate);

                // Update the User:
                user.UserName = editUser.Email;
                user.Email = editUser.Email;
                user.FirstName = editUser.FirstName;
                user.LastName = editUser.LastName;
                user.Position = editUser.Position;
                user.DepartmentID = editUser.DepartmentID;
                user.SuperiorID = editUser.SuperiorID;
                user.OfficeNumber = editUser.OfficeNumber;
                user.CellNumber = editUser.CellNumber;

                //Here we pass the byte array to user context to store in db
                user.ProfilePicture = imageData;
                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.");
            PopulateDepartmentsDropDownList(editUser.DepartmentID);
            PopulateSuperiorsDropDownList(editUser.SuperiorID);
            return View();
        } 
  • Can you add cshtml files (views)? – dima_horror Jan 13 '19 at 22:27
  • Hi dima_horror, I have added the create view to the post :) – M. Anthony Jan 13 '19 at 22:31
  • I think problem is with method parameters. Can you add method that you use to edit user? Has it the same parameters? – dima_horror Jan 13 '19 at 23:06
  • Hi dima_horror, I have added the edit controller code. I am using a different method for the edit since I'm using the user's Id to retrieve the assigned health professionals. On create I don't have an Id yet so I'm using a different method. – M. Anthony Jan 13 '19 at 23:19

1 Answers1

0

It's something strange with parameters in your methods.

Best way is to pass user object as parameter. https://stackoverflow.com/a/18005264/2114398

For quick fix you can update multi-select parameter manually, by removing selectedHealthProfessionals and selectedGroups parameters from method and then initialize them as local variables

    [HttpPost]
    public async Task<ActionResult> Create([Bind(Exclude = "ProfilePicture")]RegisterViewModel userViewModel, ApplicationUser applicationUser)
    {
        var selectedGroups = (Request.Form["selectedGroups"] ?? "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        var selectedHealthProfessionals = (Request.Form["selectedHealthProfessionals"] ?? "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

        applicationUser.HealthProfessionals = new List<HealthProfessional>();
        foreach (var healthProfessional in selectedHealthProfessionals)
        {
            var healthProfessionalToAdd = db.HealthProfessionals.Find(int.Parse(healthProfessional));
            applicationUser.HealthProfessionals.Add(healthProfessionalToAdd);
        }
        if (ModelState.IsValid)
        {
        ...
dima_horror
  • 3,098
  • 1
  • 20
  • 24