我一直试图建立一个基于DDD的应用程序,但我有一些问题。
我有一些层:-表示层- MVC -应用层-域层.
首先,我想知道我是否可以在ApplicationLayer中做到这一点(get家庭信息> get缺省消息信息>发送电子邮件>更新数据库):
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)
};
}我想得好吗?应用层负责做这项工作吗?
第二个问题是:我需要根据用户拥有的权限向表示层发送一些数据。这些特权在数据库中定义。对象族具有名称、LastName、PhoneNumber、电子邮件属性,用户可以显示/隐藏每个值。我怎么处理这件事?
我可以在应用层中这样做吗?
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
};
}注意:家族、DefaultMessage和FamilyConfiguration是在域层中创建的域对象。
你的意见是什么?
谢谢:)
编辑:注:我喜欢下面所有的答案,我用了一点:) (我不能把所有的答案标记为可接受的)。
发布于 2017-03-19 23:47:03
您的应用程序服务在#1中所做的工作是完全有效的:它用很少或根本没有业务逻辑知识来协调工作流。
然而,确实可以做的改进很少,例如:
FamilyApproved域事件并在事件处理程序中移动电子邮件发送逻辑可能是明智的。
请注意,您希望只有在域事件被持久化到磁盘之后才异步调用处理程序,并且希望将事件保存在与聚合相同的事务中。emailService.send(MessageTypes.FamilyApproved, family.getEmail())的内容。应用程序服务不必知道默认消息。DefaultMessage不是AR,那么我会考虑以不同的方式命名DefaultMessageRepository服务。至于#2,虽然授权检查可以在域中进行,但更常见的做法是将域从此类任务中释放出来,并在应用层强制执行权限。您甚至可以拥有一个专用的标识&支持有限上下文(BC)的访问。
"//ProcessConfiguration将设置为空我无法显示的属性“
该解决方案不会很好(就像实现IFamilyProperty解决方案一样),因为您的域模型会被技术授权问题所污染。如果您想应用DDD,那么模型应该尽可能忠实于无处不在的语言(UL),我怀疑IFamilyProperty是您的领域专家会提到甚至理解的东西。允许属性成为null可能也会违反一些不变量。
这种解决方案的另一个问题是,域模型很少用于查询(它是为命令构建的),因此通常更倾向于完全绕过它,而倾向于直接访问DB。在域中实现授权将阻止您轻松地执行授权。
至少出于这些原因,我认为最好在域外实现授权检查。在那里,您可以自由地使用您想要的任何实现,并且适合您的需要。例如,我认为从DTO中去掉值可能是合法的。
发布于 2017-03-20 07:04:09
我还怀疑是否可以在应用程序服务中放置一些逻辑。但是一旦我读了弗拉基米尔·霍里科夫的“域服务与应用程序服务文章”,事情就变得更干净了。它说
域服务保持域逻辑,而应用程序服务不支持域逻辑。
并以很好的例子说明了这个想法。因此,在您的情况下,我认为将这些场景放置到Application中是完全可以的,因为它不包含域逻辑。
发布于 2017-03-19 21:40:24
第1章
我通常将这个逻辑移到域层--服务层()。
因此,应用程序层只需调用:
public ApproveFamilyOutput ApproveFamily(ApproveFamilyInput input)
{
var approveService = diContainer.Get<ApproveService>(); // Or correctly injected by constructor
var result = approveService.ApproveFamily(input);
// Convert to ouput
}域服务(AppproveService类)如下所示:
public ApproveResult ApproveFamily(ApproveFamilyInput input)
{
var family = _familyRepository.GetFamily(input.Username);
family.Approve();
_familyRepository.Update(family);
bool isSaved = _familyRepository.Save();
if(isSaved)
_eventPublisher.Publish(family.raisedEvents);
// return result
}为了使其工作(并遵循六边形/洋葱体系结构),域层定义其依赖项(IFamilyRepository、IDefaultMessageRepository等)的所有接口,应用层向域层注入特定的实现。
为了表明这一点:
class FamilyApprovedHandler : IHandle<FamilyApprovedEvent>
{
private readonly IDefaultMessageRepository _defaultMessageRepository;
private readonly IEmailSender _emailSender;
private readonly IEmailProvider _emailProvider;
// ctor
public Task Handle(FamilyApprovedEvent event)
{
var defaultMessage = _defaultMessageRepository.GetDefaultMessage(MessageTypes.FamilyApproved);
var email = _emailProvider.Generate(event.Family, defaultMessage.Subject, defaultMessage.Message);
_emailSender.Send(email);
}
}https://stackoverflow.com/questions/42882053
复制相似问题