public class Parentviewmodel { public Parentviewmodel { Content = new Childviewmodel(); } public Childviewmodel Content { get; set,} } public class Childviewmodel { [required] public string Name1 { get; set,} [required] public string Name2 { get; set,} }
以下控制器发布动作:
[HttpPost] public ActionResult Create(Parentviewmodel viewmodel) { if (ModelState.IsValid) { // process viewmodel -> write something into database return RedirectToAction("Index"); } return View(viewmodel); }
现在我将一个post请求体中的以下表单值发送到与该操作对应的URL(在Fiddler Request Builder中手动):
> Content.Name1 = X.
这工作正常,Name1属性填充在viewmodel.Content中,Name2为null,模型状态无效,因为Name2是必需的.因此,验证按预期失败.
> Xontent.Name1 = X或Name1 = X或其他任何东西,以便没有任何东西绑定到viewmodel
现在viewmodel.Content不为null(因为我在构造函数中实例化它),但所有属性Name1和Name2都为null.这是预料之中的.我没想到的是模型状态是有效的,因此它通过了验证(之后导致数据库异常,因为存在非可空列).
如何改进此代码以便验证在第二种情况下也适用?
我做了三个实验:
>我已在Parentviewmodel构造函数中删除了Content的实例化,然后在上面的第二个示例中Content为null,但验证仍然通过.
>我在Content属性中添加了[required]属性(但没有删除Parentviewmodel构造函数中Content的实例化).这完全没有效果,上述两个测试的描述行为是相同的.
>我在Content属性中添加了[required]属性,并删除了Parentviewmodel构造函数中Content的实例化.这看起来像我想要的那样:在第二个测试中,Content为null,由于[required]属性,验证失败.它看起来像这样:
public class Parentviewmodel { [required] public Childviewmodel Content { get; set,} }
我现在得出结论,在Parentviewmodel构造函数中实例化Content子属性是问题的根源,并且模型绑定器本身必须实例化子属性(如果请求中没有匹配的表单字段,则必须实例化)以便具有正常工作的服务器端验证.
我在其他几个视图模型构造函数中有子属性实例化,直到现在才注意到这个问题.那么,这通常是一种不好的做法吗?还有其他方法可以解决这个问题吗?