C# MVC4中的部分模型验证

C# MVC4中的部分模型验证,c#,asp.net-mvc,validation,asp.net-mvc-4,C#,Asp.net Mvc,Validation,Asp.net Mvc 4,我有一个PartialView,它是一个用于创建或修改用户并实现ViewModelDynamicActionUserModel的表单。引用此partialView的视图显示了一个包含所有MembershipUsers的表,并提供了创建新用户Membership.CreateUser()或修改用户的Membership.UpdateUser()的能力。partialView中的表单向我的控制器发送ajax post以提交数据 我遇到的问题是,当用户被创建时,他们的用户名、电子邮件、密码和角色被序列

我有一个
PartialView
,它是一个用于创建或修改用户并实现ViewModel
DynamicActionUserModel
的表单。引用此partialView的视图显示了一个包含所有
MembershipUsers
的表,并提供了创建新用户
Membership.CreateUser()
或修改用户的Membership.UpdateUser()的能力。partialView中的表单向我的控制器发送ajax post以提交数据

我遇到的问题是,当用户被创建时,他们的用户名、电子邮件、密码和角色被序列化回控制器作为
DynamicActionUserModel.RegisterModel
并进行验证,但是当用户被修改时,密码不是可用的属性(我也不想让它在客户端修改)因此,它不是在
DynamicActionUserModel.RegisterModel
ModelState.IsValid
中设置的

也许我的模型和视图的设计需要更改,或者是否有一种方法可以在修改用户时验证模型但忽略密码?不确定这一次的最佳实践是什么

我想另一个选择是创建另一个ViewModel和另一个partialView,专门用于修改用户,但这似乎有些草率

型号

public class DynamicActionUserModel {
    public string Action { get; set; }
    public RegisterModel RegisterModel { get; set; }
}

public class RegisterModel {
    [Required]
    [Display(Name = "User Name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    public string[] SelectedRoles { get; set; }
    public MultiSelectList Roles { get; set; }

}
控制器

[HttpGet]
public ActionResult CreateUser() {
    var model = new DynamicActionUserModel {
        Action = "CreateUser",
        RegisterModel = new RegisterModel {
            Roles = new MultiSelectList(System.Web.Security.Roles.GetAllRoles())
        }
    };

    return PartialView("_UserPartial", model);
}

[HttpGet]
public ActionResult ModifyUser() {
    var model = new DynamicActionUserModel {
        Action = "ModifyUser",
        RegisterModel = new RegisterModel {
            Roles = new MultiSelectList(System.Web.Security.Roles.GetAllRoles())
        }
    };

    return PartialView("_UserPartial", model);
}

[HttpPost]
public ActionResult ModifyUser(DynamicActionUserModel model) {
    bool isEqual = true;

    if(!ModelState.IsValid) { // this is always false because password is empty
        return PartialView("_UserPartial", model);
    }

    var user = Membership.GetUser(model.RegisterModel.UserName);
    // do stuff
    Membership.UpdateUser(user);

    return Json(new {success = false});
}
查看

@using RobotDog.Models
@model IEnumerable<RobotDog.Models.UserModel>

<!-- table of users -->
<div class="modify-form">
    @Html.Action("ModifyUser")
</div>
<div class="create-user-form">
    @Html.Action("CreateUser")
</div>
@model RobotDog.Models.DynamicActionUserModel

@using(Html.BeginForm(Model.Action,"Admin", FormMethod.Post, new { @class = "ajax" })) {
    <!-- Email -->
    @Html.TextBoxFor(x => x.RegisterModel.Email, new { @class = inputSize, placeholder = "Email"})

    <!-- UserName -->
    @if(Model.Action == "ModifyUser") {
        @Html.HiddenFor(x => x.RegisterModel.UserName)
        <span class="input-xlarge uneditable-input">@Html.DisplayNameFor(x => x.RegisterModel.UserName)</span>
    } else {
        @Html.TextBoxFor(x => x.RegisterModel.UserName, new { @class = inputSize, placeholder = "User Name" })
    }

    <!-- Password -->
    @if(Model.Action == "Createuser") {
        @Html.PasswordFor(x => x.RegisterModel.Password, new { @class = inputSize, placeholder = "Password"})
    }

    <!-- Roles -->
    @Html.ListBoxFor(x => x.RegisterModel.SelectedRoles, Model.RegisterModel.Roles)

    <!-- Submit -->
    <input type="submit" value="Submit" class="btn"/>
}
@使用RobotDog.Models
@模型IEnumerable
@Html.Action(“ModifyUser”)
@Action(“CreateUser”)
局部视图

@using RobotDog.Models
@model IEnumerable<RobotDog.Models.UserModel>

<!-- table of users -->
<div class="modify-form">
    @Html.Action("ModifyUser")
</div>
<div class="create-user-form">
    @Html.Action("CreateUser")
</div>
@model RobotDog.Models.DynamicActionUserModel

@using(Html.BeginForm(Model.Action,"Admin", FormMethod.Post, new { @class = "ajax" })) {
    <!-- Email -->
    @Html.TextBoxFor(x => x.RegisterModel.Email, new { @class = inputSize, placeholder = "Email"})

    <!-- UserName -->
    @if(Model.Action == "ModifyUser") {
        @Html.HiddenFor(x => x.RegisterModel.UserName)
        <span class="input-xlarge uneditable-input">@Html.DisplayNameFor(x => x.RegisterModel.UserName)</span>
    } else {
        @Html.TextBoxFor(x => x.RegisterModel.UserName, new { @class = inputSize, placeholder = "User Name" })
    }

    <!-- Password -->
    @if(Model.Action == "Createuser") {
        @Html.PasswordFor(x => x.RegisterModel.Password, new { @class = inputSize, placeholder = "Password"})
    }

    <!-- Roles -->
    @Html.ListBoxFor(x => x.RegisterModel.SelectedRoles, Model.RegisterModel.Roles)

    <!-- Submit -->
    <input type="submit" value="Submit" class="btn"/>
}
@model RobotDog.Models.DynamicActionUserModel
@使用(Html.BeginForm(Model.Action,“Admin”、FormMethod.Post、new{@class=“ajax”})){
@TextBoxFor(x=>x.RegisterModel.Email,新的{@class=inputSize,placeholder=“Email”})
@如果(Model.Action==“ModifyUser”){
@Html.HiddenFor(x=>x.RegisterModel.UserName)
@DisplayNameFor(x=>x.RegisterModel.UserName)
}否则{
@TextBoxFor(x=>x.RegisterModel.UserName,新的{@class=inputSize,placeholder=“User Name”})
}
@if(Model.Action==“Createuser”){
@PasswordFor(x=>x.RegisterModel.Password,新的{@class=inputSize,placeholder=“Password”})
}
@(x=>x.RegisterModel.SelectedRoles,Model.RegisterModel.Roles)
}

尝试使用
ModelState。在调用
ModelState.IsValid
之前删除(“密码”)
,但正如建议的那样,如果属性并非总是必需的,则不应将其标记为必需的。

您看过吗

注意:即使在MVC4中,文档也是向后的,应该说:

确定是否存在与指定键关联或以指定键为前缀的ModelError对象

为此,我制作了一个小小的扩展方法助手:

public static class ModelStateHelpers
    {
        public static bool IsValidFor<TModel, TProperty>(this TModel model,
                                                         System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression,
                                                         ModelStateDictionary modelState)
        {
            string name = ExpressionHelper.GetExpressionText(expression);

            return modelState.IsValidField(name);
        }
    }