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

本文关键字:验证 模型 | 更新日期: 2023-09-27 18:23:41

如果client validation已完成,何时需要执行domain level validation

我将ASP.NET MVC用于我的web应用程序。我喜欢区分我的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);

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

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

有人能谈谈这个验证问题吗?

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

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

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

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

例如,如果您的应用程序不断增长,最终您向客户提供了一个API,以便以编程方式直接与应用程序交互,则必须验证域模型,因为您无法保证所使用的用户界面已将数据验证为所需的标准(甚至根本无法验证数据)。有一种观点认为,API接收到的数据应该以与验证视图模型基本相同的方式进行验证,这可能是个好主意,因为这可以实现与验证视图模式相同的目标,因此,将其定义在中心位置是理想的。

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

一般来说,我认为域模型是最重要的代码,因此也是对其状态神圣的管理。出于这个原因,我永远不会仅仅因为域模型是由本应强制有效性的表示层操作的,就认为它处于有效状态。这意味着您的域层与您的表示层紧密耦合。

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

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

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

我倾向于将客户端验证视为在UI级别对数据进行更多的净化。换句话说,例如,检查作为数字的输入字段是否由用户给定了数字。或者文本输入的长度是否满足最小长度要求。诸如此类的东西。

在域级别,您应该检查业务域规则。例如,如果用户正在输入有关新产品的详细信息,那么产品名称是否已经存在?或者,在配置新用户时,根据该用户的技能,检查该用户是否选择了一个有效的部门?这只是一些不常见的例子,但我希望它们能说明我的意思。

如果您的模型有多个客户端,则需要有一个模型验证器。例如,如果您有ASP.NET MVC调用您的模型和WPF应用程序,那么在这种情况下,在模型上设置验证逻辑是有意义的。但如果你只有一个客户,那就太过分了。