【问题标题】:Validation with DDD in SOA application using IoC使用 IoC 在 SOA 应用程序中使用 DDD 进行验证
【发布时间】:2011-09-28 00:32:05
【问题描述】:

在我的服务外观层中,我有一个服务类,其方法/操作接受 DTO(数据协定)对象。 AutoMapper 用于将此 DTO 映射到我的域对象的实例中以应用任何更改。该请求被传递到我的域服务上,该服务执行实际工作。该方法可能如下所示:

public EntityContract AddEntity(EntityContract requestContract)
{
    var entity = Mapper.Map<EntityContract, Entity>(requestContract);

    var updatedEntity = Service.AddEntity(entity);

    var responseContract = Mapper.Map<Entity, EntityContract>(updatedEntity);

    return responseContract;
}

Service 和 Mapper 属性是使用 Unity 作为 IoC 容器的构造函数注入设置的。

在执行操作时,域服务对实体进行更改,然后使用存储库来保存更改,例如:

public Entity AddEntity(Entity entity)
{
    // Make changes to entity

    Repository.Add(entity);

    // Prepare return value
}

Repository 也是使用构造函数注入设置的。

问题是数据一旦被持久化就会立即可供其他客户端使用,所以我必须确保没有无效数据被持久化。我已经阅读了 DDD (Evans) 和 Nilsson 的“蓝皮书”,但不清楚我应该采用哪种验证方法。

如果我的目标是防止实体进入无效状态,我是否应该在我的服务方法中验证 entityContract 以确保在将请求传递到我的域服务之前满足所有规则?我对此犹豫不决,因为在服务外观中定义这些规则似乎打破了封装。

我们使用委派给域服务的薄外观层的原因是,我们在 API 中公开了粗粒度接口,但通过组合细粒度域服务来支持重用。请记住,多个外观服务可能会调用相同的域服务方法,也许将这些规则委托给域服务会更好,这样我们就知道每次使用都经过验证。还是我应该在这两个地方都进行验证?

我还可以在属性设置器中设置保护措施,以防止不可接受的值将实体置于无效状态。这意味着 AutoMapper 在尝试映射无效值时会失败。但是,当没有映射任何值时,它没有帮助。

我仍然无法忘记这些规则是实体行为的一部分,并且确定对象是否有效应该封装在实体中。这是错的吗?

所以首先我需要确定何时何地执行这些验证检查。然后我需要弄清楚如何使用 DI 来实现依赖关系。

你能提供什么建议?

【问题讨论】:

    标签: validation domain-driven-design


    【解决方案1】:

    我已经阅读了 DDD (Evans) 和 Nilsson 的“蓝皮书”,但我没有 明确我应该采用哪种验证方法。

    蓝皮书从不同的角度解决问题。我认为没有使用“验证”一词,因为它是危险的overgeneralization。更好的方法是考虑对象不变量,而不是验证。对象(不仅在 DDD 中)应该自己强制执行它们的内部不变量。它不是 UI 或服务或合同或映射器或“验证框架”或对象外部的任何其他东西。不变量在内部强制执行。您可能会发现这些答案很有帮助:1234

    我还可以在属性设置器中放置防护装置,以防止 将实体置于无效的不可接受的值 状态。这意味着 AutoMapper 在尝试映射时会失败 无效值。

    您可能根本不应该关心 AutoMapper 失败或使用 AutoMapper。域对象应该封装并强制执行它们的内部不变量,如果尝试破坏它,则抛出异常。它非常简单,您不应该因为一些基础设施问题而损害域对象的简单性和表现力。 DDD 的目标不是满足 AutoMapper 或任何其他框架的要求。如果该框架不适用于您的域对象,请不要使用它。

    【讨论】:

    • 链接很棒。现在我很清楚,允许对象进入无效状态并提供错误列表(例如通过 IDataErrorInfo)的交互类型的验证属于 UI/Presentation 层(ViewModel)。而且我很擅长在我的域对象中放置警卫,以防止它们进入无效状态。但是您是否主张不要在服务和/或外观层中也进行检查,除非它们跨越多个实体/聚合?
    • 您可以根据需要对服务和 UI 进行额外检查。我的观点是域对象不应该依赖这些检查。
    • @SonOfPirate - 出于兴趣,我使用 CodeContracts 在我的域对象中强制执行不变量。
    【解决方案2】:

    您有两种类型的验证:

    1. 对象一致性:是实体的责任。实体不应允许您将它们设置为无效状态,应强制执行依赖关系,值应在范围内。您必须设计类的方法和属性以及构造函数以不允许出现无效状态。

    2. 业务角色验证:这种类型的验证需要服务器处理,例如检查 id 可用性、电子邮件唯一性等。在持久化之前,这些类型的验证应在服务器中作为验证器或规范进行处理。

    【讨论】:

    • 我提供第三种方法:UI 验证。这是为了向用户提供交互式反馈。我认为这是更多验证框架(如数据注释和企业库)的目标,而不是实现其他两种类型。
    • 是的,你是对的,我只是专注于域层的验证,在 UI 中也有一个验证,它将使用任何 UI 兼容的验证框架在视图模型或表示模型中处理
    • 我同意你必须有一个自我验证的域。您是否将一些验证器注入到域对象中以进行复杂(业务规则)验证?您是否在应用层对命令 (DTO) 进行了基本验证?
    • 是的,当它是真正的域验证时,我确实将一些验证器注入到域中,并在域对象处于不一致状态时保持域的正确性。对于应用层,如果您想向 UI 显示用户友好的验证消息或处理基于工作流的验证,则可以选择进行验证。
    猜你喜欢
    • 2015-11-21
    • 2013-03-22
    • 2023-03-25
    • 2016-04-18
    • 2012-03-28
    • 2013-03-04
    • 2020-09-25
    • 2018-07-25
    • 2017-06-21
    相关资源
    最近更新 更多