DDD与客户端验证

9
假设你有一个应用程序,采用领域模型模式、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个回答

5
在DDD中,领域通常是自我验证的。换句话说,对象不允许处于无效状态。值对象在这里非常有帮助。它们简单地封装格式化规则。例如,您可以拥有一个名为ZipCode的类,保证始终良好形式。作为一项额外的职责,它可以具有静态方法,如ZipCode.TryParseZipCode.Validate,将任意字符串作为参数进行验证。这样,验证逻辑集中在一个地方。如果您的领域对象可以直接从UI访问,则无需在其他地方复制此逻辑。这适用于Fat客户端(Windows Forms,WPF)。不幸的是,当Web客户端需要执行验证而无需往返到服务器时,无法避免一些重复。

4

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

我在我的原始偏执博客文章中写到了这个问题。如果您创建这样的类,您的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
    }
}

不需要使用注释,因为它们实际上鼓励你复制验证逻辑。

比较以下代码示例:


3

我还没有遇到一个全面的验证解决方案。原因之一是,由于应用程序层的不同,验证逻辑可能会有微妙的差别。例如,域层实施的并非所有规则都可以在客户端执行,因此总会有一些情况,在客户端验证可能通过,但仍需要显示来自域层的验证消息。

然而,ASP.NET MVC中的验证模型是可扩展的,您可以将其扩展以支持其他验证规则或甚至是DataAnnotations之外的验证框架。这里是一个将Enterprise Library Validation block与ASP.NET MVC集成的示例,但正如文章所指出的那样,并未实现客户端验证。另一个方法是在您的域层中使用DataAnnotations属性。DataAnnotations命名空间并不绑定于ASP.NET MVC。

然而,这些方法面临的挑战是将验证规则从域对象传播到视图模型。理论上,您可以扩展AutoMapper,使得来自域模型的验证规则传递到视图模型类,但是实现和维护的成本可能超过了该解决方案的好处。

Fluent Validation 框架可以作为全面验证解决方案的起点。有许多使用 ASP.NET MVC 和该框架的 示例


谢谢你的回答和提供的链接。你说得对,我已经思考了一段时间并且在过去几天里尝试了一些示例应用程序,今天我才意识到试图自动化整个客户端验证实现过程可能有点过度设计。好消息是,DataAnnotations 命名空间可以用于在域实体或视图模型对象中实现验证逻辑。这将解决验证规则的集中化问题。但最终我们还是需要自己在客户端实现实际的验证,这不是什么大问题。 - Nexus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接