DDD&客户端验证

时间:2011-08-06 10:49:20

标签: .net domain-driven-design client-side-validation n-tier-architecture

假设您有一个使用域模型模式,DDD和许多其他设计模式的应用程序。假设我们有许多解决方案,如下所示:

  • Solution.Model
  • Solution.Repository
  • Solution.Services
  • Solution.Presentation
  • Solution.UI.Web

用户体验层将是Solution.UI.Web,我们假设它将是一个ASP.NET WebForms应用程序。你如何强制执行客户端验证?

有许多事情需要考虑:

首先,我们不应该点击应用程序/数据库服务器向客户端返回任何验证错误,但我们也可以实现服务器端验证,但我们需要客户端验证。

其次,我们不希望在用户体验层上实现验证规则。那是因为如果您的应用程序是WebApp,然后您决定创建一个WinApp客户端,那么您将不得不再次实施验证规则 - >维护噩梦。

一种简单的方法是使用ViewModel对象(将被发送到客户端的域实体的展平视图)实现验证逻辑,然后在命中应用程序/数据库服务器之前验证这些对象。

另一种方法,我见过在不同的应用程序中多次使用的方法,就是生成一组验证错误消息并将该集合发送给客户端。那没关系,但是有问题。只是一个简单的验证错误摘要消息不会发生,特别是如果您有大数据输入表单。

现在,ASP.NET MVC框架让生活变得更加轻松。您可以使用EF + DataAnnotations,而MVC Scaffolding框架可以为您完成大部分工作。但是如果你想创建一个MVC应用程序并使用jQuery和JavaScript实现你的验证逻辑就是这种情况。

但是,如果你需要一种更通用的方法来实现可以在不同的应用程序中使用和使用的验证框架,比如WinForms和WebForms呢?

只是为了澄清,我正在寻找的是一组设计模式/原则和/或技术/框架,以实现验证框架,该框架可以使用您的域模型实施,然后在您的客户端应用程序上实施。并且,我不想只返回关于破坏的规则或任何东西的字符串错误消息的集合,我希望能够在验证失败时更新我的​​数据绑定控件(TextBox,ComboBox,DateTimePicker等),以便用户体验层会更直观(如果你愿意的话)。

我已经看到了一些实现和框架,我已经使用了ASP.NET MVC客户端验证一段时间了,所以我的答案与MVC或JavaScript验证没有任何关系。

3 个答案:

答案 0 :(得分:5)

在DDD中,域通常是自我验证的。换句话说,不允许对象处于无效状态。值对象在这里有很多帮助。它们只是封装格式规则。例如,您可以保证 ZipCode 类始终保持良好状态。作为一项额外的职责,它可以使用静态方法,如 ZipCode.TryParse ZipCode.Validate ,它将采用任意字符串作为参数并进行验证。这种方式验证逻辑集中在一个地方。如果您的域对象可以直接从UI访问,则不需要在其他任何地方复制此逻辑。胖客户端就是这种情况(Windows窗体,WPF)。遗憾的是,当需要执行验证而不向服务器进行往返运行时,无法避免Web客户端的某些重复。

答案 1 :(得分:4)

您应该将验证逻辑封装在代表您的领域知识的简单类中。

我在primitive obsession博客文章中写到了这一点。以下是创建此类类时ASP.NET MVC控制器的外观:

public class CustomerController : Controller
{
    [HttpPost]
    public ActionResult CreateCustomer(CustomerInfo customerInfo)
    {
        Result<Email> emailResult = Email.Create(customerInfo.Email);
        Result<CustomerName> nameResult = CustomerName.Create(customerInfo.Name);

        if (emailResult.Failure)
            ModelState.AddModelError("Email", emailResult.Error);
        if (nameResult.Failure)
            ModelState.AddModelError("Name", nameResult.Error);

        if (!ModelState.IsValid)
            return View(customerInfo);

        Customer customer = new Customer(nameResult.Value, emailResult.Value);
        // Rest of the method
    }
}

无需使用注释,因为它们本质上鼓励您复制验证逻辑。

比较这些代码示例:

答案 2 :(得分:2)

我没有遇到过全面的验证解决方案。其中一个原因是验证逻辑可能根据应用层的不同而略有不同。例如,并非所有由域层强制执行的规则都可以在客户端强制执行,因此始终存在客户端验证可能通过的情况,但您仍需要显示从域层传播的验证消息。

但是,ASP.NET MVC中的验证模型是可扩展的,您可以扩展它以支持其他验证规则或事件除DataAnnotations之外的验证框架。 Here是将Enterprise Library Validation块与ASP.NET MVC集成的示例,但正如文章所指出的,未实现客户端验证。另一种方法是在域层中使用DataAnnotations属性。 DataAnnotations命名空间与ASP.NET MVC无关。

然而,这些方法的挑战是将验证规则从域对象传播到视图模型。从理论上讲,您可以扩展AutoMapper,以便从域模型中继承验证规则以查看模型类,但实现和维护的成本可能超过此解决方案的好处。

Fluent Validation框架可以作为全面验证解决方案的起点。在ASP.NET MVC中使用这个框架有很多examples