Передача значений ViewModel в метод действия контроллера MVC при нажатии кнопки или ActionLink

У меня есть страница asp.net/razor с несколькими раскрывающимися списками, и я пытаюсь создать кнопку или ссылку действия, которая вызывает метод с именем «AssignRole» в классе «AccountController» и передает значения, выбранные в раскрывающихся списках, в этот метод. Я экспериментировал с различными подходами, но ни один из них не работает правильно:

    @model SpecSelRepos.Models.AccountViewModels.ManageRolesViewModel

    <fieldset>
        <label for="selectUserName">Users:</label>
        <select asp-for="ManageRolesUser" asp-items="Model.Users"></select>
        &nbsp;
        <label for="selectRoleName">Roles:</label>
        <select asp-for="ManageRolesRole" asp-items="Model.Roles"></select>
        &nbsp;

        @*button 1*@
        @using (Html.BeginForm("AssignRole", "Account"))
        {
            <input type="submit" value="Add User to Role" name="buttonAddUserToRole">


         }

        @*button 2*@
        <button class="btn btn-info" type="button" name="assignRole" onclick="location.href='@Url.Action("AssignRole", "Account", new { email = Model.ManageRolesUser, role = Model.ManageRolesRole })'"></button>

        @*link 1*@
        @Html.ActionLink("Assign Role", "AssignRole", "Account", new { email = Model.ManageRolesUser, role = Model.ManageRolesRole }, null)

        @*link 2*@
        @Html.ActionLink("Assign Role", "AssignRole", "Account", new { email = Model.ManageRolesUser, role = Model.ManageRolesRole })

    </fieldset>

В классе AccountController у меня есть следующий метод действия:

public async Task<IActionResult> AssignRole(string email, string role)
        {
            ApplicationUser user = GetUserByEmail(email);
            if(null == user)
            {
                return Content("No user with given email:" + email);
            }
            // if the role exists, assign the role to the user
            if (await _roleManager.RoleExistsAsync(role))
            {
                if(!await _userManager.IsInRoleAsync(user, role))
                {
                    await _userManager.AddToRoleAsync(user, role);
                    return Content("Role assigned: " + GetUserRoles(user));
                }
                else
                {
                    return Content ("User is in role: " + role + ": " + GetUserRoles(user));
                }
            }
            else
            {
                return Content("Role: " + role + " does not exist");
            }
        }

Нажатие кнопки 1 не имеет видимого эффекта. Кнопка 2 и обе ссылки вызывают метод AssignRole, но все 3 выдают ошибку с нулевым значением:

ArgumentNullException: Value cannot be null.
 Parameter name: email
Microsoft.AspNetCore.Identity.UserManager.FindByEmailAsync(string email)
SpecSelRepos.Controllers.AccountController.GetUserByEmail(string email) in AccountController.cs
+                return _userManager.FindByEmailAsync(email).Result;
SpecSelRepos.Controllers.AccountController+<AssignRole>d__10.MoveNext() in AccountController.cs
+                ApplicationUser user = GetUserByEmail(email);

Таким образом, кажется, что метод вызывается по желанию, но значения из модели представления передаются как нулевые, а не значения, выбранные в раскрывающихся списках.

Это класс модели представления:

public class ManageRolesViewModel
    {
        private readonly UserManager<ApplicationUser> _userManager;

        public ManageRolesViewModel(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
        {
            _userManager = userManager;
            Users = new SelectList(userManager.Users.ToList());
            Roles = new SelectList(roleManager.Roles.ToList());
        }

        public SelectList Users;
        public SelectList Roles;
        public string ManageRolesUser { get; set; }//contains the specific user the user selects
        public string ManageRolesRole { get; set; }//contains the specific role the user selects

        public List<ApplicationUser> GetUsersInRole(string role)
        {
            var users = _userManager.GetUsersInRoleAsync(role).Result.ToList();
            return users;
        }
    }

Некоторая помощь будет оценена по достоинству.


person Steve W    schedule 13.04.2018    source источник


Ответы (1)


Измените свое представление, чтобы оно выглядело следующим образом: вместо этого я использовал форму с методом и действием формы, это обеспечит сериализацию любых входных данных внутри формы в параметры, соответствующие тому же имени, что и они.

@model WebApplication3.Models.ManageRolesViewModel

<fieldset>
    @using (Html.BeginForm("AssignRole", "Account", FormMethod.Get))
    {
        <span>
            <label for="email">Users:</label>
            @Html.DropDownList("email", @Model.Users)
        </span>
        <span>
            <label for="role">Roles:</label>
            @Html.DropDownList("role", @Model.Roles)
        </span>

        <input class="btn btn-info" type="submit" name="assignRole"/>
    }

</fieldset>

Поскольку параметры «email» и «role» совпадают с параметрами в подписи контроллера, выбранные идентификаторы будут переданы вверх (не текстовые значения).

Это, конечно, связано с предикатом, что selectList, который вы передаете в представление, имеет заполненные «dataValueField» и «dataTextField».

Я также (не обязательно) приписал ваш метод AssignRoles с помощью: [HttpGet]

Но это только для многословия. Я сторонник постоянства :)

person James Robert Pattison    schedule 14.04.2018
comment
Превосходно! Спасибо друг. - person Steve W; 14.04.2018