我正在尝试扩展使用EF6和MVC生成的用户注册表单,我希望能够显示显示为单选按钮的用户角色列表,我相信我已经完成了。然而,我遇到的麻烦是当我将表单发布回控制器时,它没有将所选选项绑定回视图模型。我做错了什么?
我的视图模型:
public class RegisterViewModel
{
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Username")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 4)]
public string Username { get; set; }
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "FirstName")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 2)]
public string FirstName { get; set; }
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Surname")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 2)]
public string Surname { get; set; }
//Other fields removed to save space
[Required]
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
}
我有一个我想要传递给视图的身份角色列表,如下所示:
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
var model = new RegisterViewModel();
model.UserRoles = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>()).Roles.ToList();
return View(model);
}
在视图中我会显示如下角色:
<div class="panel-body">
@foreach (var item in Model.UserRoles)
{
<div class="col-md-8">
<div>
@Html.RadioButtonFor(m => m.UserRoles, item.Name)
@Html.DisplayFor(m => item.Name, new { @class = "col-md-3 control-label" })
</div>
</div>
}
@Html.ValidationMessageFor(m => m.UserRoles, "", new { @class = "text-danger" })
</div>
但是,当提交表单时,模型永远不会有效,因为角色永远不会被绑定。 (或者至少那些我相信的)任何想法?
答案 0 :(得分:0)
您不希望将单选按钮绑定到值列表,您需要将模型更改为角色列表和所选角色,如此
//Other fields removed to save space
[Required]
[Display(Name = "Role")]
public IdentityRole UserRole { get; set; }
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
然后你创建像这样的单选按钮
@Html.RadioButtonFor(m => m.UserRole, item.Name)
然后,这会将所选值回发给UserRole属性。
注意:我认为你还需要使用radiobutton的值来让它填充回UserRole,因为我认为item.Name不起作用。您可能希望使用名称回发到字符串字段,然后在控制器的post方法中查找适当的角色。
答案 1 :(得分:0)
我调查了这个(甚至测试了理论,因为我有一个可用),这是不可能的。您可以将所选对象的任何子属性绑定到视图模型,而不是整个对象。
这是我的reference来自堆栈溢出。
答案 2 :(得分:0)
Html控件(input,textarea,select)回发他们的名字/值对。在您的情况下,与单选按钮关联的表单数据将为UserRoles: someValue
。
假设您的POST方法为public ActionResult Register(RegisterViewModel model)
,DefaultModelBinder
首先初始化RegisterViewModel
的实例,然后找到匹配的表单数据名称/值对,并尝试设置property {{的值1}}到字符串UserRoles
当然会失败,因为"someValue"
是一个复杂的对象而UserRoles
变成了UserRoles
。
除非您创建自定义null
和/或ModelBinder
,否则无法将html控件绑定到复杂对象,即使这样,它也只会设置您模型的一个属性,因为您只回发了一个值。
您需要创建一个视图模型,其中的属性表示您要在视图中显示/编辑的内容,例如(假设typeof ValueProviders
具有属性IdentityRole
)
int ID
然后在视图中
public class RegisterViewModel
{
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Username")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 4)]
public string Username { get; set; }
....
// For binding the selected roles
[Required(ErrorMessage = "Please select a role")]
public int ID SelectedRole { set; set; }
// For displaying the available roles
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
}
当您回发时,您可以从模型@model yourAssembly.RegisterViewModel
@using (Html.BeginForm())
{
....
foreach(var role in Model.UserRoles)
{
@Html.RadioButtonFor(m => m.SelectedRole, role.ID, new { id = role.Name })
<label for="@role.Name">@role.Name</label>
}
@Html.ValidationMessageFor(m => m.SelectedRole)
....
}
属性中获取所选角色的ID。