21

如果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

4 回答 4

14

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

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

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

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

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

于 2013-07-29T16:26:59.797 回答
7

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

最好从领域模型开始向外思考(洋葱架构)。这一切背后的原因是域模型随着时间的推移而变化的可能性最小,并且充当应用程序的核心,将层与彼此的缺陷隔离开来。

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

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

于 2013-07-24T18:45:46.550 回答
2

我倾向于认为客户端验证更多的是在 UI 级别清理数据。换言之,检查例如作为数字的输入字段是否被用户赋予了数字。或者文本输入的长度是否满足最小长度要求。类似的东西。

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

于 2013-07-18T10:51:24.217 回答
0

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

于 2013-07-18T10:44:33.337 回答