验证嵌套的ViewModel

Sla*_*uma 8 asp.net validation asp.net-mvc asp.net-mvc-3

我有两个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, }
}
Run Code Online (Sandbox Code Playgroud)

以下控制器发布动作:

[HttpPost]
public ActionResult Create(ParentViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        // process viewModel -> write something into database
        return RedirectToAction("Index");
    }
    return View(viewModel);
}
Run Code Online (Sandbox Code Playgroud)

现在我将后续请求正文中的以下表单值发送到与该操作对应的URL(在Fiddler Request Builder中手动):

  • Content.Name1 = X

    这样工作正常,Name1属性填写viewModel.Content,Name2null和模型状态无效,因为Name2是必需的.因此,验证按预期失败.

  • Xontent.Name1 = X名1 = X或任何这样,任何被绑定到viewModel

    现在viewModel.Content是不是null(因为我在构造函数实例化的话),但所有的属性Name1Name2null.这是预料之中的.我也没有想到的是,模型的状态是有效的,所以它通过验证(导致数据库异常后,因为有非空列).

如何改进此代码以便验证在第二种情况下也适用?

我做了三个实验:

  • 我已删除的实例化的ContentParentViewModel构造函数中,则Contentnull在第二示例中的上方,但验证仍然通过.

  • 我添加了一个[Required]属性的Content属性(但没有删除的实例化ContentParentViewModel构造函数).这完全没有效果,上述两个测试的描述行为是相同的.

  • 我添加了一个[Required]到属性Content属性删除的实例化ContentParentViewModel构造函数.这看起来像我想要的那样:在第二个测试Contentnull,由于[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, }
    }
    
    Run Code Online (Sandbox Code Playgroud)

我现在得出结论,ContentParentViewModel构造函数中实例化子属性是问题的根源,并且模型绑定器本身必须实例化子属性(如果请求中没有匹配的表单字段,则必须实例化)以便正确使用工作服务器端验证.

我在其他几个视图模型构造函数中有子属性实例化,直到现在才注意到这个问题.那么,这通常是一种不好的做法吗?还有其他方法可以解决这个问题吗?

Sla*_*uma 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, }
}
Run Code Online (Sandbox Code Playgroud)

我现在在几个地方使用它,没有发现任何问题。