C# 向模型中添加隐藏字段时,MVC范围属性失败
我有一个父模型,其中包含子模型用于预填充视图上字段的属性。 我想将属性移动到它所属的子模型中,但是当我这样做时,另一个属性的range属性失败。 当我有一个仅用于在EditorTemplate上隐藏的属性时,为什么range属性验证失败 模型看起来像C# 向模型中添加隐藏字段时,MVC范围属性失败,c#,asp.net-mvc,asp.net-mvc-3,mvc-editor-templates,editorfor,C#,Asp.net Mvc,Asp.net Mvc 3,Mvc Editor Templates,Editorfor,我有一个父模型,其中包含子模型用于预填充视图上字段的属性。 我想将属性移动到它所属的子模型中,但是当我这样做时,另一个属性的range属性失败。 当我有一个仅用于在EditorTemplate上隐藏的属性时,为什么range属性验证失败 模型看起来像 public class ParentModel { public SubModel subModel { get; set; } } public class SubModel { public uint? DefaultValu
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>
使用子模型中的DefaultValue属性,即使在窗体上禁用RangeId,也会激发RangeId的Range属性。这将导致ModelState.IsValid为false。
当我将DefaultValue属性向上移动到ParentModel时,RangeId的Range属性不再激发(因为该字段是禁用的)。这将导致ModelState.IsValid为true,因为RangeId从未进行过验证计算。您认为正在发生的任何事情都不会发生。服务器端Model.IsValid不关心任何问题,禁用客户端的控件也不会直接影响它(尽管它可能会受到间接影响,我们将在下面看到)。如果发布了嵌套表单字段,并且嵌套对象具有必需的属性,则始终会进行验证 更可能的是,这里真正的问题是,当您在子模型中有DefaultValue时,然后当您将模型提交给父模型时,模型绑定器会创建子模型的实例,因为它包含DefaultValue的值。将其移动到父对象并禁用RangeId时,没有要发布的值,因此不会创建子模型,因此不会进行验证 也就是说,我的猜测是,当您将DefaultValue移动到父级时,子模型在回发时为null,因此,由于没有要验证的实例,所以验证不会失败,特别是因为您没有持久化EnableRange值
所以你真的有几个问题。首先,在客户端禁用控件不会在服务器上禁用验证。其次,如果没有向服务器发布嵌套表单字段,则不会创建嵌套对象,也不会进行验证(因此,如果非常小心,验证可能会被禁用,作为一种副作用)。第三,如果您确实发布了一些嵌套表单字段,但没有发布其他字段,则将创建验证嵌套对象,并对由于禁用而未发布的字段进行验证。如果发布视图呈现的html片段,可能会有所帮助。很难理解你想用js做什么。不清楚你在这里做什么。如果禁用控件,它不会回发,在这种情况下,
ModelState
将无效,因为RangedId
的值为0
听起来是使用该接口的一个很好的理由。同意。看起来逻辑相当复杂。服务器端逻辑可以在IValidatableObject中复制,也可以创建一些来整合逻辑。
public ActionResult Create(TViewModel model)
{
try
{
if (ModelState.IsValid)
{
//Do Something Meaningful
}
//Redisplay the view
}
}