【问题标题】:ModelState.IsValid returns false when it should be trueModelState.IsValid 在应该为真时返回假
【发布时间】:2010-11-08 19:03:33
【问题描述】:

我有一个非常简单的 MVC 2 表单。它有两个下拉列表,用户和角色。无论我选择什么,员工下拉列表都会通过验证,而角色下拉列表则不会。尽管我计划实现一个,但没有默认的“空”选项,这就是为什么我需要验证才能工作。它无法通过客户端和服务器验证。我只是不明白为什么一个会工作而一个不工作!

形式:

<% using (Html.BeginForm()) {%>

    <%:Html.ValidationSummary(true) %>
    <%:Html.EditorFor(model => model.User, new { AllEmployees = Model.AllEmployees, RoleList = Model.RoleList })%>

    <p>
        <input type="submit" value="Add New User" />
    </p>

    <% } %>

<% Html.EndForm(); %>

编辑器模板:

<tr>
    <td>
        <div class="editor-label">
            <%: Html.LabelFor(model => model.UserId) %>
            <%: Html.RequiredMarkFor(model => model.UserId) %>
        </div>   
    </td>    
    <td>    
    <div class="editor-field">
        <%: Html.DropDownListFor(model => model.UserId, new SelectList(ViewData["AllEmployees"] as IEnumerable, "UserId", "DisplayName", Model.UserId)) %>
        <%: Html.ValidationMessageFor(model => model.UserId>
    </div>    
    </td>       
</tr>     

<tr>
    <td>
        <div class="editor-label">
            <%: Html.LabelFor(model => model.AccessLevel)%>
            <%: Html.RequiredMarkFor(model => model.AccessLevel)%>
        </div>   
    </td>    
    <td>    
        <div class="editor-field">
            <%: Html.DropDownListFor(model => model.AccessLevel, new SelectList(ViewData["RoleList"] as IEnumerable, Model.AccessLevel))%>
            <%: Html.ValidationMessageFor(model => model.AccessLevel)%>
        </div>    
    </td>       
</tr> 

元数据:

    [DisplayName("Employee")]
    [Required(ErrorMessage = "Please select an employee.")]
    [StringLength(8, ErrorMessage = "User Id must be less than 8 characters.")]
    [DisplayFormat(ConvertEmptyStringToNull = false,
                            HtmlEncode = true)]
    [DataType(DataType.Text)]
    public object UserId { get; set; }


    // Validation rules for Access Level
    [DisplayName("Role")]
    [Required(ErrorMessage = "Please select the role for this user.")]
    [StringLength(15, ErrorMessage = "Role must be under 15 characters.")]
    [DisplayFormat(ConvertEmptyStringToNull = false,
                            HtmlEncode = true)]
    [DataType(DataType.Text)]
    public object AccessLevel { get; set; }

获取操作:

    List<String> roles = (from o in txDB.Users
                                      select o.AccessLevel).Distinct().ToList(); 

    var viewModel = new UserViewModel
    {
        User = new User(),
        AllEmployees = empList,
        RoleList = roles
    };
    return View(viewModel);

发布动作:

    [HttpPost]
    [AuthorizeAttribute(Roles="Administrator")]
    public ActionResult Create(User user)
    {
        if(!ModelState.IsValid)
        {
            //ModelState is invalid
            return View(new User());
        }
        try
        {
           //do stuff
        }
    }

所需的辅助方法(来自Define markup for [Required] fields in View in ASP.NET MVC 2.0):

    public static string RequiredMarkFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
    {
        if(ModelMetadata.FromLambdaExpression(expression, helper.ViewData).IsRequired)
            return "*";
        else
            return string.Empty;
    } 

【问题讨论】:

    标签: validation asp.net-mvc-2


    【解决方案1】:

    Post方法应该如下获取Server端验证...

    [HttpPost]
    [AuthorizeAttribute(Roles="Administrator")]
    public ActionResult Create(User user)
    {
        if(!TryUpdateModel(user))
        {
           // Model is INVALID
           return View(user);
        }
        else
        {
            // ModelState is VALID
            // Do stuff
        }
    }
    

    else 可能是多余的,这取决于你在做什么,但这应该会让你继续前进。 在您需要的&lt;% using Html.BeginForm() %&gt; 上方的视图中

    <% Html.EnableClientValidation(); %>
    

    你还需要参考我认为的脚本,MicrosoftAjax 和 MicrosoftMvcValidation

    【讨论】:

    • TryUpdateModel 如何参考 ModelState 工作?是的,所有脚本都被引用并添加了客户端验证,只是没有在代码中显示。
    • 好的,我没有看到代码所以我不想假设。 TryUpdateModel 只是我一直使用的一种方法,因为有人在这里向我推荐了它。
    【解决方案2】:

    首先:你有两个结束表单标签

    如果你使用

    <% using (Html.BeginForm()) {%>
    <% } %>
    

    你不需要使用这个

    <% Html.EndForm(); %>
    

    关于您的验证问题,您只为您的 User 属性使用编辑器,这是唯一由模型绑定器绑定的编辑器

    <%:Html.EditorFor(model => model.User, new { AllEmployees = Model.AllEmployees, RoleList = Model.RoleList })%>
    

    尝试用 EditorForModel 替换之前的代码,因为您的编辑器模板用于模型类。

    所以你的表单应该改变

    <% using (Html.BeginForm()) {%>
    
        <%:Html.ValidationSummary(true) %>
        <table>
            <%:Html.EditorForModel()%>
        </table>
        <p>
            <input type="submit" value="Add New User" />
        </p>
    <% } %>
    

    你就完成了!

    【讨论】:

    • 仅为用户使用编辑器的目的是因为视图使用视图模型以便让我通过两个下拉列表。您是否建议我只向用户强烈键入视图,并在视图数据中传递列表?
    • 您的视图是对 ViewModel 的强类型。您的 EditorTemplate 为两个下拉菜单创建 html 标记。如果您只使用Html.EditorFor(model =&gt; model.User...,那么即使您正在传递所有视图模型,您也会告诉视图只需将一个属性绑定到视图。
    • 我试过了——同样的效果。顺便感谢您指出 EndForm 冗余,没有注意到这一点。还有其他想法吗?我即将注释掉 [Required] 注释并继续前进:P
    • RequiredMarkFor 是什么?您还可以发布您的 POST 方法的签名吗?
    • 奇怪的是,现在它似乎在服务器上验证,而不是在客户端。
    猜你喜欢
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 2016-12-20
    相关资源
    最近更新 更多