Asp.net mvc 了解域实体中的域服务、应用程序服务和行为(方法)
我们一直在为分层应用程序开发一个体系结构。我们计划有一个ASP.NETMVC表示层,它同时服务于移动浏览器和“普通”浏览器。也就是说,如果用户在移动设备上导航到站点,我们需要相同的ASP.NET MVC表示层来提供针对移动浏览器优化的视图,同时,如果用户使用其台式机/笔记本电脑,则提供针对台式机/笔记本电脑浏览器优化的“常规”视图。目前,我们不打算支持本地移动应用程序,但我们可能会在未来增加这一功能。此外,该体系结构将具有域模型层-域实体、域服务等、应用程序服务,以及使用EF code first POCO和存储库和工作单元模式的数据层-所有标准域模型类型的设计 然而,我一直在试图找出域服务、应用程序服务和域实体中的行为(方法)之间的区别,因为它们适用于我们正在开发的系统。下面是我们系统中用于检查的高级用例 我们有报告和报告组。这两个实体之间存在多对多关系。DB表是:Reports Jct_Reports_ReportGroups ReportGroups,域实体如下所示:Asp.net mvc 了解域实体中的域服务、应用程序服务和行为(方法),asp.net-mvc,architecture,domain-driven-design,service-layer,Asp.net Mvc,Architecture,Domain Driven Design,Service Layer,我们一直在为分层应用程序开发一个体系结构。我们计划有一个ASP.NETMVC表示层,它同时服务于移动浏览器和“普通”浏览器。也就是说,如果用户在移动设备上导航到站点,我们需要相同的ASP.NET MVC表示层来提供针对移动浏览器优化的视图,同时,如果用户使用其台式机/笔记本电脑,则提供针对台式机/笔记本电脑浏览器优化的“常规”视图。目前,我们不打算支持本地移动应用程序,但我们可能会在未来增加这一功能。此外,该体系结构将具有域模型层-域实体、域服务等、应用程序服务,以及使用EF code firs
Report class :
public string ReportName { get; set; }
...
public virtual ICollection<ReportGroup> ReportGroups { get; set; }
ReportGroup class :
public string GroupName { get; set; }
...
public virtual ICollection<Report> Reports { get; set; }
报告类:
公共字符串ReportName{get;set;}
...
公共虚拟ICollection报告组{get;set;}
报表组类:
公共字符串组名{get;set;}
...
公共虚拟ICollection报告{get;set;}
当然,用户可以创建报告(不创建报告组),也可以创建包含一个或多个报告的报告组。此外,用户还可以删除报告。当这种情况发生时,会发生很多事情。首先,我们检查报告是否在任何报告组中(单个报告可以在许多不同的报告组中)。如果在任何报告组中找到该报告,我们将遍历每个报告组并从报告组中删除该报告(通过从Jct_Reports_ReportGroups表中删除一行)。然后,对于包含要删除的报告的每个报告组,我们检查该报告组中是否还有其他报告。如果报告组中没有其他报告,我们也会删除该报告组(通过从ReportGroups表中删除该行)。如果报告组中还有其他报告,我们不会删除该报告组。如果所有这些操作都成功,我们将删除用户选择的要删除的报告(通过删除报告表中的行)。最后,向用户显示一条消息,说明报告删除是否成功
我希望这是一个足够的用例,可以帮助我们理解整个应用程序的一小部分
我在某个地方读到过,域服务封装的业务逻辑并不适合域对象,也不是典型的CRUD操作,而应用程序服务被外部使用者用来与您的系统对话——如果使用者需要访问CRUD操作,它们将在此处公开。但是,我只是不理解POCO域实体中会有哪些方法(业务逻辑),哪些业务逻辑会被视为域服务并包含在业务层中,哪些业务逻辑会被视为应用服务层中包含的应用服务。因此,我的主要问题是:鉴于上述用例,关于如何在域实体中划分域服务、应用程序服务和行为(方法)的建议是什么?这是一个相当大的问题 我更喜欢以下非严格的指导原则: 应用程序服务:假设我们有一组描述用户与系统交互的用例。假设我们有
登录
和现金转账
案例,有特定的输入和输出;它们还描述了成功和失败的场景。有了这些,我们通常有一个应用程序服务规范:我将公开LoginResul登录(name,pass)
和TransferResult-cashtrasfer(from,to,amount)
方法,它们或多或少具有相同的输入和输出以及成功/失败行为
很明显,为了实现用例,应用程序服务调用BL(但添加了安全性和其他特定于应用程序的检查)
域服务:正如您所描述的:“不自然地适合域对象”
有了CashTrasnfer用例,我们必须:
- “从”加载帐户
- 将帐户“加载到”
- 检查“来自”余额“//可能返回错误
- 验证帐户访问权限(锁定等)//可能返回错误
- 从“来源”中提取“金额”
- 将金额记为“至”
- (理想情况下,这应该是一笔“业务”交易)
TransferService
特别是关于报表/报表组功能-它可以是实体范围,因为没有非逻辑引用(所有项都可以从报表访问): 或者在报表服务和实体之间拆分(引用存储库可能会有问题):
这是一个相当大的问题 我更喜欢以下非严格的指导原则: 应用程序服务:假设我们有一组描述用户与系统交互的用例。假设我们有
登录
和现金转账
案例,有特定的输入和输出;它们还描述了成功和失败的场景。有了它,我们通常有一个应用程序服务规范:我将公开b
Report.Remove() {
foreach(group in Groups) {
group.RemoveReport(this);
}
repository.Remove(this);
}
Group.RemoveReport(report) {
reports.Remove(report);
if(reports.Count == 0)
repository.Remove(this);
}
Report.RemoveFromAllGroups() {
foreach(group in Groups) {
group.RemoveReport(this);
if(group.IsEmpty)
//add to collection to return
}
}
Service.Remove(report)
{
var emptyGroups = report.RemoveFromAllGroups();
reportRepo.Remove(report);
groupRepo.Remove(emptyGroups);
}