c# - DDD(领域驱动设计)应用层

标签 c# .net domain-driven-design

我一直在尝试构建一个基于 DDD 的应用程序,但我有一些问题。

我有一些层: - 表示层 - MVC - 应用层 - 域层 ...

首先,我想知道我是否可以在ApplicationLayer中执行此操作(获取家庭信息>获取默认消息信息>发送电子邮件>更新数据库):

public ApproveFamilyOutput ApproveFamily(ApproveFamilyInput input)
        {
            Family family = _familyRepository.GetFamily(input.Username);
            family.Approve();

            DefaultMessage defaultMessage = _defaultMessageRepository.GetDefaultMessage(MessageTypes.FamilyApproved);

            _email.Send(family.GetEmail(), defaultMessage.Subject, defaultMessage.Message);

            _familyRepository.Update(family);
            bool isSaved = _familyRepository.Save();

            return new ApproveFamilyOutput()
            {
                Errors = Helper.GetErrorIfNotSaved(isSaved)
            };
        }

我思考得好吗?应用程序层负责完成这项工作吗?

第二个问题是:我需要根据用户拥有的权限向表示层发送一些数据。这些权限在数据库中定义。例子: - 对象 Family 具有名称、姓氏、电话号码、电子邮件属性,用户可以显示/隐藏每个值。 我该如何处理这个问题?

我可以在应用层做类似的事情吗:

public GetFamilyOutput GetFamily(GetFamilyInput input)
        {
            Family family = _familyRepository.GetFamily(input.Username);

            FamilyConfiguration familyConfiguration = _familyConfigurationRepository.GetConfigurations(family.Id);

            //ProcessConfiguration will set to null the properties that I cannot show
            family.ProcessConfiguration(familyConfiguration);

            return new GetFamilyOutput
            {
                //Map Family Object to the GetFamilyOutput
            };
        }

注意:Family、DefaultMessage 和 FamilyConfiguration 是在域层内创建的域对象。

你的意见是什么?

谢谢:)

编辑: 注意:我喜欢下面的所有答案,并且我使用了其中的一些答案:)(我无法将所有答案标记为可接受)

最佳答案

您的应用程序服务在 #1 中所做的事情是完全有效的:它协调工作流程,几乎不需要业务逻辑知识。

但是,确实可以进行一些改进,例如:

  1. 我没有看到任何交易?仅应在成功提交交易后发送电子邮件。

  2. 发送电子邮件可以被视为家人批准的副作用。我想业务专家可能会说:“一个家庭获得批准后,通过电子邮件通知感兴趣的各方”。因此,明智的做法是发布 FamilyApproved 域事件并在事件处理程序中移动电子邮件发送逻辑。

    请注意,您希望仅异步调用处理程序 当域事件被持久化到磁盘并且你想要持久化之后 同一事务中的事件作为聚合。

  3. 您可能可以将邮寄过程进一步抽象为 emailService.send(MessageTypes.FamilyApproved, family.getEmail()) 之类的内容。应用程序服务不必了解默认消息。

  4. 存储库通常专用于聚合根 (AR),如果 DefaultMessage 不是 AR,那么我会考虑以不同的方式命名 DefaultMessageRepository 服务。

对于#2,虽然授权检查可以在域中完成,但更常见的做法是将域从此类任务中解放出来并在应用程序层中强制执行权限。您甚至可以拥有支持限界上下文 (BC) 的专用身份和访问权限。

"//ProcessConfiguration will set to null the properties that I cannot show"

该解决方案不会那么好(就像实现 IFamilyProperty 解决方案一样),因为您的域模型会受到技术授权问题的污染。如果您希望应用 DDD,那么模型应该尽可能忠实于通用语言 (UL),并且我怀疑您的领域专家会提及甚至理解 IFamilyProperty。允许属性变为 null 也可能会违反一些不变量。

这种解决方案的另一个问题是,域模型很少适用于查询(它是为命令构建的),因此通常最好完全绕过它并倾向于直接访问数据库。在域中实现授权会阻止您轻松执行此操作。

至少出于这些原因,我认为最好在域外实现授权检查。在那里,您可以自由使用您想要的任何实现并适合您的需求。例如,我认为从 DTO 中剥离值可能是合法的。

关于c# - DDD(领域驱动设计)应用层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42882053/

相关文章:

asp.net-mvc - 将 "domain services"放在域模型项目中的位置

c# - 如何在保持持久性无知的同时创建丰富的领域对象?

c# - DateTime.TryParse 问题,日期由 a.m 而不是 am 组成

c# - uwp,c# Dns.GetHostAddresses() 不解析主机文件中的主机名

c# - 在 Timer.Elapsed 事件上更新 MainWindow

c# - 扩展方法与反射(reflection)

c# - AOP(面向方面​​的编程)和日志记录。它真的很实用吗?

c# - C#/.NET 中的二次规划

.net - 如何判断数组类型?

design-patterns - 为什么存储库不应该包含事务逻辑?