在分层应用程序中验证

Tom*_*sen 7 c# validation model-view-controller domain-driven-design repository

我想知道在ASP.NET MVC应用程序中验证数据库约束(例如UNIQUE)的最佳方法是什么,在构建时考虑到DDD,底层是Application Layer(应用程序服务),Domain Layer(域模型)和基础设施层(持久性逻辑,日志记录等).

我一直在查看大量的DDD样本,但是他们中没有提到的是如何在存储库中进行验证(我想这是这种类型的验证适合的地方).如果你知道任何这样做的样品,请分享它们将非常感激.

更具体地说,我有两个问题.你会如何进行实际验证?您是否通过查询数据库明确检查客户名称是否已存在,或者您是否尝试将其直接插入数据库并捕获错误(如果有的话)(看起来很乱)?我更喜欢第一个,如果选择它,是应该在存储库中完成,还是应该是应用程序服务的工作?

检测到错误时,如何将其传递给ASP.NET MVC,以便能够很好地通知用户错误?最好使用,ModelStateDictionary以便在表格上轻松突出错误.

在Microsoft Spain的N-Lyered应用程序中,他们使用IValidatableObject界面,最简单的属性验证放在实体本身,例如:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var validationResults = new List<ValidationResult>();

    if (String.IsNullOrWhiteSpace(this.FirstName))
        validationResults.Add(new ValidationResult(Messages.validation_CustomerFirstNameCannotBeNull, new string[] { "FirstName" }));

    return validationResults;
}
Run Code Online (Sandbox Code Playgroud)

在实体持久化之前,将调用Validate消息以确保属性有效:

void SaveCustomer(Customer customer)
{
    var validator = EntityValidatorFactory.CreateValidator();

    if (validator.IsValid(customer)) //if customer is valid
    {
        _customerRepository.Add(customer);
        _customerRepository.UnitOfWork.Commit();
    }
    else
        throw new ApplicationValidationErrorsException(validator.GetInvalidMessages<Customer>(customer));
}
Run Code Online (Sandbox Code Playgroud)

然后可以在MVC应用程序中捕获ApplicationValidationErrorsException,并且可以解析验证错误消息并将其插入到ModelStateDictionary.

我可以将所有验证逻辑添加到SaveCustomer方法中,例如,使用给定列(UNIQUE)查询数据库是否已存在客户.也许这没关系,但我宁愿validator.IsValid(或类似的东西)会为我做这个,或者在Infrastructure层再次执行验证(如果它属于这里,我不确定).

你怎么看?你怎么做呢?我非常有兴趣深入了解分层应用程序中的不同验证技术.


可能的解决方案#1

如果验证逻辑不能在表示层完成(如Iulian Margarintescu建议)并且需要在服务层完成,那么如何将验证错误传递到表示层?

微软在这里有一个建议(见清单5).您如何看待这种方法?

Iul*_*scu 2

您提到了 DDD,但 DDD 的含义远不止实体和存储库。我假设您熟悉埃里克·埃文斯先生的《领域驱动设计》一书,我强烈建议您重新阅读有关战略设计和限界上下文的章节。另外,Evans 先生有一个非常精彩的演讲,名为“自这本书以来我对 DDD 的了解”,您可以在这里找到。Greg Young 或 Udi Dahan 关于 SOA、CQRS 和事件源的讨论也包含大量有关 DDD 和应用 DDD 的信息。我必须警告您,您可能会发现一些事情,这些事情会改变您对应用 DDD 的看法。

现在,关于验证的问题 - 一种方法可能是用户在“名称”字段中键入某些内容后立即查询数据库(使用定向到应用程序服务的 Ajax 调用),并尝试在以下情况下建议替代名称:他输入的一个已经存在。当用户提交表单时,尝试将记录插入数据库并处理任何重复键异常(在存储库或应用程序服务级别)。由于您已经提前检查了重复项,因此出现异常的情况应该相当罕见,因此任何像样的“我们很抱歉,请重试”消息都应该这样做,除非您有很多用户,否则他们可能永远不会看到它。

Udi Dahan 的这篇文章也提供了一些有关验证的信息。请记住,这可能是您对企业施加的约束,而不是企业对您施加的约束 - 也许允许同名客户注册而不是拒绝他们可以为企业提供更多价值。

还要记住,DDD 更多的是关于业务而不是技术。您可以执行 DDD 并将应用程序部署为单个程序集。服务之上、实体之上、存储库之上、数据库之上的客户端代码层已经以“好”设计的名义被滥用了很多次,却没有任何理由说明为什么它是一个好设计。

我不确定这会回答您的问题,但我希望它能指导您自己找到答案。