简体   繁体   English

MVC4中的部分模型验证

[英]Partial Model Validation in MVC4

I have a PartialView that is a form used to create or modify a user and implements the ViewModel DynamicActionUserModel . 我有一个PartialView ,它是一个用于创建或修改用户并实现ViewModel DynamicActionUserModel的表单。 The view that referrences this partialView shows a table of all MembershipUsers and gives the ability to create a new user Membership.CreateUser() or modify a user 'Membership.UpdateUser()`. 引用此partialView的视图显示了所有MembershipUsers的表,并且能够创建新用户Membership.CreateUser()或修改用户'Membership.UpdateUser()`。 The form in the partialView does an ajax post to my controller to submit data. partialView中的表单向我的控制器发送ajax帖子以提交数据。

The issue I'm running into is that when a user is created their userName, email, password and role is serialized back to the controller as DynamicActionUserModel.RegisterModel and validated, but when a user is modified, password is not a property that is available (nor do I want to make it available to modify on the client side) so it isn't set in DynamicActionUserModel.RegisterModel and ModelState.IsValid is always false. 我遇到的问题是,当用户创建其userName,电子邮件, 密码和角色作为DynamicActionUserModel.RegisterModel被序列化回控制器并进行验证,但是当用户被修改时,密码不是可用的属性(我也不想让它在客户端修改)因此没有在DynamicActionUserModel.RegisterModelModelState.IsValid设置它总是false。

Perhaps the design of my model and view needs to change, or is there a way to validate the model but ignore password when a user is being modified? 也许我的模型和视图的设计需要改变,或者有没有办法验证模型但是在修改用户时忽略密码? Not sure what the best practice is for this one. 不确定这个最佳做法是什么。

I guess another option would be to create another ViewModel and another partialView specifically for modifying a user but that seems sloppy. 我想另一个选择是创建另一个ViewModel和另一个专门用于修改用户的partialView,但这似乎很草率。

Model 模型

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; }

}

Controller 调节器

[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});
}

View 视图

@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>

PartialView PartialView

@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"/>
}

在调用ModelState.IsValid之前尝试使用ModelState.Remove("password") ,但是如果不总是需要属性, 这里建议您不要将其标记为必需。

Have you looked at ModelState.IsValidField ? 你看过ModelState.IsValidField吗?

Note: even as of MVC4 the documentation is backwards and should say : 注意:即使在MVC4中,文档也是向后的,应该说:

Determines whether there are any ModelError objects that are associated with or prefixed with the specified key. 确定是否存在与指定键关联或前缀的任何ModelError对象。

I've made a little extension method helper for this: 我为此做了一个小的扩展方法助手:

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);
        }
    }

Usage is simple: 用法很简单:

 bool billingValid = model.IsValidFor(x => x.CheckoutModel.BillingAddress, ModelState);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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