我有一个带有自定义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
方法中设置断点,并在调试器中看到FieldToCheck
false - 而不是我提交的内容!
Model Binder绑定错了吗?如果是这样,为什么?为什么验证器中的绑定值不正确,但控制器中的正确?
这导致我的ViewModel验证失败每当 DateTime字段留空(提交NULL)。但是如果那个布尔值为false,我甚至不会在我的表单中显示 DateTime字段 - 我不希望用户在该字段中提交任何内容。< / p>
编辑:这似乎只发生了与布尔,但无论布尔/条件字段的创建位置如何,它都会一直发生。
Model Binder在验证之前是否未绑定布尔成员?
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),但仍然会导致同样的问题。如果我在IsValid
验证器中的RequiredIf
方法中设置断点,则无论提交的数据如何,我的所有布尔值都为false。如果我在Create
中的Controller
方法中设置断点,则我的布尔值设置正确。
我还测试了Boolean
和bool
数据类型。它似乎没有任何影响。
EDIT4:
我实际上并未找出问题的原因或真正的解决方案,但我确实找到了解决方法。
所以,显然当我RequiredIf(AnyBooleanValue, AnythingButTrue)
时会出现问题。如果将DesiredValue
设置为除<{1}}之外的任何,则Model Binder会将ViewModel中的所有布尔值设置为默认值 - {{1 - 无论提交什么。我尝试了多种方法 - true
,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; }
}
时,我都会使用jQuery将IsConditionalFieldRequired
设置为FieldToCheck
的倒数。< / p>
(我将其添加为编辑而不是答案,因为我认为这不是一个真正的解决方案,只是一个可行的解决方法。显然,这不是最有说服力的完成任务的方法。)
答案 0 :(得分:1)
这是一个古老的问题,但是我今天遇到了一个同样的问题,当时我使用的是RequiredIf
属性,而ValidationContext.ObjectInstance
属性没有正确的绑定值。
在我看来,这是由于我的视图模型类具有可设置一些默认属性值的构造函数。在自定义属性代码中,属性值是在构造函数中设置的,而在控制器中,属性值来自发布的表单。
我通过删除构造函数并在视图中设置默认值来解决此问题。