【问题标题】:Custom DataAnnotation Binding Wrong Value自定义 DataAnnotation 绑定错误值
【发布时间】:2015-09-16 16:18:52
【问题描述】:

我有一个带有自定义 RequiredIf DataAnnotation 实现的 C# 应用程序,如下所示:

public class RequiredIf : RequiredAttribute {
    private String PropertyName { get; set; }
    private Object DesiredValue { get; set; }

    public RequiredIf (String property_name, Object desired_value) {
        PropertyName = property_name;
        DesiredValue = desired_value;
    }

    protected override ValidationResult IsValid (object value, ValidationContext context) {
        Object instance = context.ObjectInstance;
        Type type = instance.GetType();
        Object prop = type.GetProperty(PropertyName);
        Object property_value = type.GetProperty(PropertyName).GetValue(instance, null);
        if ( property_value.ToString() == DesiredValue.ToString() ) {
            ValidationResult result = base.IsValid(value, context);
            return result;
        }


        return ValidationResult.Success;
    }
}

这似乎在几乎所有情况下都有效。

我有一个要验证的 ViewModel。 ViewModel 有一个子类。基本实现是:

public class ViewModel {
    .........
    public class ChildObject {
        [RequiredIf("FieldToCheck", false)]    // note that it's only required if the value is FALSE!
        DateTime? ConditionalField { get; set; }  // could be NULL
        Boolean FieldToCheck { get; set; }
    }
    ..........
}

当我提交表单并将 FieldToCheck 设置为 true 时,我的 ViewModel 验证在此 RequiredIf 上仍然失败。我可以在控制器中查看 ViewModel 变量中的值并验证它是true。但是,我可以在 DataAnnotation 的 IsValid 方法中设置断点,然后在调试器中看到 FieldToCheckfalse - 不是我提交的!

Model Binder 绑定错了吗?如果是这样,为什么?还有为什么validator中的绑定值不正确,而controller中正确

这导致我的 ViewModel 验证失败每当 DateTime 字段留空(提交 NULL)。但是,如果该布尔值是错误的,我什至不会在我的表单中显示 DateTime 字段——我不希望用户在该字段中提交任何内容。

编辑:这似乎只发生在布尔值上,但无论在哪里创建布尔值/条件字段,它都会始终如一地发生。

模型绑定器是否在验证之前不绑定布尔成员?

EDIT2:

在视图中,我有一个用于发布数据的标准表单:

@Model ViewModel

@using ( Html.BeginForm("Create", "Controller", FormMethod.Post ) {

    .........

    @Html.DropDownListFor(m => m.FieldToCheck, Model.FieldToCheckList)

    .........

    <button type="submit">Submit</button>

}

控制器:

public class Controller : Controller {

    [HttpPost]
    public ActionResult Create (ViewModel view_model) {
        // I set a breakpoint here, and if I submit FieldToCheck = true, the debugger shows that FieldToCheck is, indeed, true.
        if ( ModelState.IsValid ) {
            // save to db
            return View();
        }
        return View();
   }
}

我有一个方法可以在渲染表单之前初始化 ViewModel 中的字段,并在其中设置FieldToCheckList 如下:

view_model.FieldToCheckList = new List<SelectListItem> {
    new SelectListItem { Text = "Yes", Value = Boolean.TrueString },
    new SelectListItem { Text = "No", Value = Boolean.FalseString }
}

所以我使用select 来填充值。但是,我尝试了多个其他表单元素(包括将 HiddenFor 静态设置为 true),但仍然会导致相同的问题。如果我在RequiredIf 验证器的IsValid 方法中设置断点,那么无论提交的数据如何,我的所有布尔值都是假的。如果我在ControllerCreate 方法中设置断点,我的布尔值设置正确。

我还测试了Booleanbool 数据类型。好像没什么影响。

EDIT4:

我实际上并没有弄清楚问题的原因或真正的解决方案,但我确实找到了解决方法。

所以,显然问题发生在我执行RequiredIf(AnyBooleanValue, AnythingButTrue) 时。如果 DesiredValue 设置为 anything 除了true,则模型绑定器会将 ViewModel 中的 all 布尔值设置为默认值 - false - 不管是什么已提交。我尝试了多种方法-RequiredIf(FieldToCheck, "False")RequiredIf(FieldToCheck, !true) 等。没有任何效果。但是如果我这样做RequiredIf(FieldToCheck, true),值就会正确绑定!

所以解决方法是添加一个新字段:

public class ViewModel {
    public Boolean FieldToCheck { get; set; }
    public Boolean IsConditionalFieldRequired { get; set; }
    [RequiredIf("IsConditionalFieldRequired",true)]
    public string ConditionalField { get; set; }
}

在视图中,我将IsConditionalFieldRequired 作为隐藏字段,并且每当更改FieldToCheck 时,我使用jQuery 将IsConditionalFieldRequired 设置为FieldToCheck 的倒数。

(我将其添加为编辑而不是答案,因为我认为这不是一个真正的解决方案,只是一个可行的解决方法。显然这不是完成工作的最雄辩的方式。)

【问题讨论】:

  • 您是使用 mvc 发布表单还是通过 javascript 发布表单?
  • 我正在使用标准 HTML 表单发布数据。所以是的,我正在使用 MVC。似乎模型绑定器没有正确绑定布尔值,因为调试器(在 IsValid 方法中)显示 all 布尔值设置为 false;但是,这些值在控制器方法中被正确绑定。
  • 可以添加相关的html吗?
  • 检查 if ( property_value.ToString() == DesiredValue.ToString() ) { 中的值 - 可能是一个案例问题 - "False""false" - 但实际使用布尔值而不是字符串值会好得多
  • 请注意,一旦您使用 C# 6,请切换到 nameof(FieldToCheck) 而不是 "FieldToCheck",以便您获得类型感知和重命名安全性!

标签: c# asp.net-mvc entity-framework validation


【解决方案1】:

这是一个老问题,但我今天遇到了同样的问题,我使用了 RequiredIf 属性,而 ValidationContext.ObjectInstance 属性没有正确的绑定值。

在我的情况下,结果证明是因为我的视图模型类有一个构造函数,它设置了一些默认属性值。在自定义属性代码中,属性值是在构造函数中设置的值,但在控制器中,属性值来自发布的表单。

我通过删除构造函数并在视图中设置默认值来解决它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    相关资源
    最近更新 更多