将隐藏字段添加到模型时,MVC范围属性失败

时间:2015-01-22 17:21:22

标签: c# asp.net-mvc asp.net-mvc-3 mvc-editor-templates editorfor

我有一个父模型,其中包含子模型用于预填充视图上的字段的属性。 我想将属性移动到它所属的子模型中,但是当我这样做时,另一个属性的范围属性会失败。 当我有一个仅用于在EditorTemplate上隐藏的属性时,为什么范围属性未通过验证?

模型看起来像

public class ParentModel
{
    public SubModel subModel { get; set; }
}
public class SubModel
{
    public uint? DefaultValue { get; set; }

    [Required]
    [Range(1,100)]
    public uint RangedId { get; set;}

    public bool EnableRange { get; set; }
}

视图(EditorTemplate)看起来像

@model SubModel
@Html.HiddenFor(model => model.DefaultValue)
@Html.TextBoxFor(model => model.RangeId)
<script>
     $('#EnableRange').change(function() {
         if($('#EnableRange').val()){
             // remove the disabled attribute from the RangeId Field
         } else {
             // add the disabled attribute from the RangeId Field
         }
     }
</script>

控制器看起来像

public ActionResult Create(TViewModel model)
{
    try
    {
        if (ModelState.IsValid)
        {
            //Do Something Meaningful
        }
        //Redisplay the view
    }
}

使用SubModel中的DefaultValue属性,即使在窗体上禁用RangeId,RangeId的范围属性也会触发。这会导致ModelState.IsValid为false。 当我将DefaultValue属性移动到ParentModel时,RangeId的Range属性不再触发(因为该字段是禁用的)。这导致ModelState.IsValid为true,因为从不评估RangeId进行验证。

1 个答案:

答案 0 :(得分:2)

无论你认为发生什么,都不会发生。服务器端Model.IsValid不关心任何事情,也不会直接影响客户端禁用控件(尽管它可能会间接受到影响,我们将在下面看到)。如果发布嵌套表单字段并且嵌套对象具有必需属性,则始终会进行验证。

更可能的是,这里的真正问题是当你在子模型中有DefaultValue时,那么当你将模型提交给父模型时,模型绑定器会创建一个SubModel实例,因为它包含DefaultValue的值。当您将其移动到父级并禁用RangeId时,没有值要发布,因此不会创建任何SubModel,因此不会进行验证。

也就是说,我的猜测是当你将DefaultValue移动到父级时,SubModel在回发时为空,因此没有要验证的实例,验证没有任何失败,特别是因为你没有持久化EnableRange值。 / p>

所以你真的有几个问题。首先,禁用客户端上的控件不会禁用服务器上的验证。其次,如果没有向服务器发布嵌套表单字段,则不会创建嵌套对象,也不会进行验证(因此在这方面,如果您非常小心,可以禁用验证作为副作用)。第三,如果您发布了一些嵌套的表单字段而不发布其他字段,则验证然后将创建嵌套对象,并且对未被发布的字段进行验证,因为它们已被禁用。