查看模型验证与域模型验证

时间:2013-07-18 10:38:46

标签: c# asp.net .net asp.net-mvc asp.net-mvc-3

如果client validation完成,则必须执行domain level validation

我将ASP.NET MVC用于我的网络应用程序。我想区分我的domain modelsview models。我的域模型包含来自我的数据库的数据,我的视图模型包含我的视图/页面上的数据。

让我们说我正在处理客户数据。

我的数据库中会有一个名为Customers的表。

我将有一个客户类,看起来像这样:

public class Customer
{
     public int Id { get; set; }

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateOfBirth { get; set; }
}

我将创建一个客户视图模型,仅代表我在视图中的数据:

[Validator(typeof(CustomerCreateViewModelValidator))]
public class CustomerCreateViewModel
{
     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateOfBirth { get; set; }
}

我将有一个接受我的CustomerCreateViewModel的创建视图,并将我的输入字段绑定到我的视图模型:

@model MyProject.ViewModels.Customers.CustomerCreateViewModel

@using (Html.BeginForm())
{
     <table>
          <tr>
               <td>
                    @Html.TextBoxFor(x => x.FirstName)
                    @Html.ValidationMessageFor(x => x.FirstName)
               </td>
          </tr>
          <tr>
               <td>
                    @Html.TextBoxFor(x => x.LastName)
                    @Html.ValidationMessageFor(x => x.LastName)
               </td>
          </tr>
     </table>

     <button id="SaveButton" type="submit">Save</button>
}

如您所见,我的CustomerCreateViewModelValidator包含验证规则。用户在文本框中输入了一些数据后,将单击“提交”按钮。如果某些字段为空,则验证失败。如果输入了所有必填字段,则验证成功。然后,我会将视图模型中的数据映射到我的域模型,如下所示:

Customer customer = Mapper.Map<Customer>(viewModel);

我采用这个客户域模型并将其传递到我的存储库层,然后将数据添加到我的表中。

什么时候需要在域模型上进行验证?我在我的视图模型上进行了所有验证。我可以在将数据添加到数据库之前验证我的域模型中的数据,但是看到它在视图模型上验证了它不会只是在客户端复制相同的验证吗?

有人可以就此验证问题分享一些看法吗?

4 个答案:

答案 0 :(得分:11)

始终在两个级别进行验证。

您需要验证视图模型,因为如果他们做错了,您希望尽可能快速,轻松地反馈给用户。如果模型无效,您也不想打扰其余的域逻辑。

但是,一旦验证了视图模型,您还需要验证域中的所有内容是否满意。对于简单模型,这些检查可能是相同的,因此它看起来像复制逻辑,但是一旦您的应用程序增长,因此您可能有多个用户界面,或使用相同域模型的许多不同应用程序,它变得如此重要在域内检查。

例如,如果您的应用程序增长,最终为客户提供API以编程方式直接与应用程序交互,则验证域模型成为必需,因为您无法保证所使用的用户界面已验证数据达到您需要的标准(甚至根本不需要验证)。有一种说法认为API接收的数据应该与验证视图模型的方式大致相同,这可能是一个好主意,因为它实现了与视图模型验证相同的目标。但无论路径(从UI或API),您都希望始终保证数据有效,因此在中心位置定义是理想的。

两个级别的验证目标也不同。我希望通过视图模型验证来告知我所有问题(例如缺少名字,姓氏太长,DoB不是日期)。但是,我认为域逻辑可以在第一个错误上失败,并报告那个错误。同样,对于简单模型,可能会收集所有错误并将其全部报告回来,但是应用程序越复杂,预测所有错误就越困难,特别是如果逻辑将根据数据而改变。但是,只要只有好的数据过去,那应该没问题!

答案 1 :(得分:6)

作为一般规则,我认为域模型是最重要的代码,因此管理其状态为圣。出于这个原因,我永远不会假设域模型处于有效状态只是因为它是由一个应该强制执行有效性的表示层操作的。这意味着您的域图层与您的表示层紧密耦合。

最好从域模型开始思考(onion architecture)。所有这一切背后的原因是域模型最不可能随着时间的推移而发生变化,并充当应用程序的核心,从而隔离彼此缺陷的层。

因此,从强制执行其自身有效性的域模型开始,您将面临重复验证代码的问题。有一些方法可以避免这种情况。例如,您的视图模型可能尝试创建域对象并转换作为验证失败而抛出的任何异常。验证器也可以被提取和重用。根据您的使用情况,您必须查看哪种方式最适合您。请注意保持简单。也许,如果您的用例不是这样,那么简单地复制验证可能是最难维护的。请记住,重复数据删除会增加复杂性

我见过代码库,其中只有域层处理验证和代码库,其中在域和表示层中处理验证。我倾向于简单地复制验证逻辑,因为我已经看到有意义地将域验证错误很好地映射到上下文用户界面是多么困难。

答案 2 :(得分:2)

我倾向于将客户端验证视为在UI级别更加清理数据。换句话说,检查例如作为数字的输入字段由用户给出数字。或者文本输入的长度是否满足最小长度要求。这样的东西。

在域级别,您应该检查业务域规则。例如,如果用户输入有关新产品的详细信息,产品名称是否已存在?或者根据用户的技能,在配置新用户时检查用户是否选择了有效的部门?这只是空中的例子,但我希望他们能够了解我的意思。

答案 3 :(得分:0)

如果您的模型有多个客户端,则需要一个模型验证器。例如,如果您有ASP.NET MVC调用模型和WPF应用程序,在这种情况下,在模型上使用验证逻辑是有意义的。但在你的情况下,你只有一个客户会有点矫枉过正。