我创建了一个基础设施,这是我们新的内部网络项目,并试图遵循几乎所有最佳实践。另外,我想提一下,这是我第一次从零创建架构。
目前,我的基础架构的第一个版本已经准备好并且运行良好。但我想在下一个版本实现有界上下文结构。
我试图解释当前的情况。
DbCore:负责数据操作。实体框架5代码首先使用。只有一个DbContext类,并且在其中定义了所有DbSet。另外,GenericRepository模式和Unit of Work模式基于以下接口实现。
IGenericRepository
public interface IGenericRepository<TEntity>
where TEntity : class {
void Delete(object id);
void Delete(TEntity entityToDelete);
System.Collections.Generic.IEnumerable<TEntity> Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<System.Linq.IQueryable<TEntity>, System.Linq.IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
System.Collections.Generic.IEnumerable<TEntity> GetAll();
TEntity GetByID(object id);
System.Collections.Generic.IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters);
void Insert(TEntity entity);
void Update(TEntity entityToUpdate);
}
IUnitOfWork
public interface IUnitOfWork {
void Dispose();
IGenericRepository<Test> TestRepository {
get;
}
IGenericRepository<Log> LogRepository {
get;
}
void Save();
}
模型:负责存储DbCore和Entity Framework的实体模型 域:代表业务逻辑层还存储存储在Models项目中的实体对象的DTO。目前业务逻辑存储在Service类中,实现了以下接口 IService
public interface IService<TEntity> {
IEnumerable<TEntity> Get();
TEntity GetByID(int id);
void Insert(TEntity entity);
}
此服务类通过ctor参数获取UnitOfWork并用于操作。 Automapper也实现了将实体对象转换为DTO,反之亦然。 从现在开始,所有上层不再对实体模型感兴趣,只使用DTO。所以几乎所有项目(包括api和web)都引用了这个项目。
常见:负责存储常用的库,如日志记录。
WebCore:负责为基于Web的项目(如API或MVC)存储常用库。还包含基于MVC的项目的扩展,处理程序和过滤器。
Api: ASP.Net MVC Web API项目代表服务层。使用域层并为客户提供服务。 控制器将IService接口作为ctor参数,并使用它通过域层访问数据层。
Web:基于ASP.Net MVC 4的Web项目,负责与用户的交互。使用Api方法访问数据。所有控制器都有一个名为IConsumeRepository的接口,它通过HttpClient连接API。
public interface IConsumeRepository<TEntity> {
Task<TEntity> Create(TEntity TestInfo);
Task Delete(int id);
Task<IEnumerable<TEntity>> Get();
Task<TEntity> Get(int id);
TEntity New();
Task<TEntity> Update(TEntity TestInfo, int entityId);
}
Autofac对所有项目都适用于IoC和DI。
目前这是我目前的基础设施,我想我解释了需要评估的所有内容。
现在我想弄清楚以下事情,
问题1:是否有任何不得以我使用的方式进行实施?
问题2:实施有界上下文的最佳方法是什么?我最近观看了Julie Lerman的视频并审阅了大量示例项目。我看到从DbContext派生BC的常见事物。但我无法确定。因为我以为BC应该在域(业务逻辑)层而不是在DbCore(数据访问)层。
问题3:正如我上面提到的,我的Api和Web项目使用DTO,因此它们都需要引用域层。但我不喜欢它,因为我正在使用API从UI中分离业务层,并再次为实体耦合它们。但我找不到比这更好的方法。
这成了一个很长的问题,但如果你与我分享你的想法以创造更好的建筑,我将非常高兴。
答案 0 :(得分:30)
问题1 :假设您拥有复杂的业务领域和重要的业务逻辑,那么您必须将域层与基础架构问题隔离开来,这是值得的。但是,情况往往并非如此。如果您主要只是将数据从数据库移动到UI并再次返回,那么这就是过度工程,您应该寻找具有较少移动部件的东西。
问题2:您有多少种不同的域模型(使用不同的普遍存在的语言)?一?二?三?对于每种型号,尽可能将其与其他型号和基础设施问题隔离开来。
Eric Evans将有界上下文定义为语言边界(引自他的书):A BOUNDED CONTEXT界定了特定模型的适用性 团队成员对所拥有的内容有清晰的共识 保持一致以及它与其他背景的关系。在那之内 背景,努力使模型在逻辑上统一,但不要担心 关于在这些范围之外的适用性。在其他背景中,其他 模型适用于术语,概念和规则的差异, 和UBIQUITOUS LANGUAGE的方言。
DBContext可能指向正确的方向,但请记住它是基础架构工件,不是域概念。它“代表了工作单元和存储库模式的组合,使您能够查询数据库并将更改组合在一起,然后将这些更改作为一个单元写回到商店。”_(来自MSDN Docs)。
DDD是关于域建模:使用模型来解决复杂业务领域中的硬业务问题。从技术考虑中获得模型边界可以感觉像尾巴摇摆着狗。从概念上定义模型的边界,然后相应地调整您的技术基础架构。
问题3: DTO可以是强制执行上下文边界的好方法,例如API。然后,API可以作为其他模型的反腐败层。人们通常将它们用于UI的原因是避免将UI概念渗透到域模型中。
不要寻求完美的建筑。并且意识到“最佳实践”实际上只是基于特定情况的指南。遵循其他更有经验的人所提出的指导原则,并了解您的情况可能略有不同。当您发现摩擦时,请使用您对重构设计决策的期望。例如,如果稍后您发现UI的DTO过度,则删除它们。随时随地简化。