我有一个父模型,其中包含子模型用于预填充视图上的字段的属性。 我想将属性移动到它所属的子模型中,但是当我这样做时,另一个属性的范围属性会失败。 当我有一个仅用于在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进行验证。
答案 0 :(得分:2)
无论你认为发生什么,都不会发生。服务器端Model.IsValid不关心任何事情,也不会直接影响客户端禁用控件(尽管它可能会间接受到影响,我们将在下面看到)。如果发布嵌套表单字段并且嵌套对象具有必需属性,则始终会进行验证。
更可能的是,这里的真正问题是当你在子模型中有DefaultValue时,那么当你将模型提交给父模型时,模型绑定器会创建一个SubModel实例,因为它包含DefaultValue的值。当您将其移动到父级并禁用RangeId时,没有值要发布,因此不会创建任何SubModel,因此不会进行验证。
也就是说,我的猜测是当你将DefaultValue移动到父级时,SubModel在回发时为空,因此没有要验证的实例,验证没有任何失败,特别是因为你没有持久化EnableRange值。 / p>
所以你真的有几个问题。首先,禁用客户端上的控件不会禁用服务器上的验证。其次,如果没有向服务器发布嵌套表单字段,则不会创建嵌套对象,也不会进行验证(因此在这方面,如果您非常小心,可以禁用验证作为副作用)。第三,如果您发布了一些嵌套的表单字段而不发布其他字段,则验证然后将创建嵌套对象,并且对未被发布的字段进行验证,因为它们已被禁用。