我有两个ViewModel(简化):
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);
}
现在我将一个帖子请求正文中的以下表单值发送到与该操作相对应的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
。这是预料之中的。我所做的不期望的是模型状态是有效,因此它通过了验证(之后导致数据库异常,因为存在不可为空的列)。
如何改进此代码,以便验证在第二种情况下也有效?
我做了三次实验:
我在Content
构造函数中删除了ParentViewModel
的实例化,然后在上面的第二个示例中Content
为null
,但验证仍然通过。< / p>
我在[Required]
属性中添加了Content
属性(但未删除Content
构造函数中ParentViewModel
的实例化)。这完全没有效果,上述两个测试的描述行为是相同的。
我在[Required]
属性中添加了Content
属性,并且删除了Content
构造函数中ParentViewModel
的实例化。这看起来像我想要的那样:在第二个测试中Content
是null
,由于[Required]
属性,验证失败。它看起来像这样:
public class ParentViewModel
{
[Required]
public ChildViewModel Content { get; set, }
}
public class ChildViewModel
{
[Required]
public string Name1 { get; set, }
[Required]
public string Name2 { get; set, }
}
我现在得出结论,在Content
构造函数中实例化ParentViewModel
子属性是问题的根源,并且模型绑定器本身必须实例化子属性(否则,如果没有匹配请求中的表单字段,以便正确运行服务器端验证。
我在其他几个视图模型构造函数中有子属性实例化,直到现在才注意到这个问题。那么,这通常是一种不好的做法吗?还有其他方法可以解决这个问题吗?
答案 0 :(得分:0)
ModelState.IsValid告诉您是否已将任何模型错误添加到ModelState。
默认模型绑定器会为基本类型转换问题添加一些错误,例如为“int”传递非数字。您可以根据您使用的任何验证系统更完整地填充ModelState。我建议查看数据注释以验证ViewModel,因为它运行良好。
此语法可能有误或有旧。 ModelState.AddModelError(“key”,Exception)
转述自 What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?
答案 1 :(得分:0)
第三种解决方案很好:
public class ParentViewModel
{
[Required]
public ChildViewModel Content { get; set, }
}
public class ChildViewModel
{
[Required]
public string Name1 { get; set, }
[Required]
public string Name2 { get; set, }
}
我现在在几个地方使用它,并没有发现任何问题。