8

我已经为我们全新的 Intranet 项目创建了一个基础架构,并尝试遵循几乎所有的最佳实践。我还想提一下,这是我第一次从零开始创建架构。

目前我的基础设施的第一个版本已经准备好并且运行良好。但我想在下一个版本中实现有界上下文结构。

我试图在下面解释当前的情况。

DbCore:负责数据操作。Entity Framework 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);
    }

工作单位

 public interface IUnitOfWork {
        void Dispose();
        IGenericRepository<Test> TestRepository {
            get;
        }
        IGenericRepository<Log> LogRepository {
            get;
        }
        void Save();
    }

Models:负责存储 DbCore 和 Entity Framework Domain 的实体模型:表示业务逻辑层还存储存储在 Models 项目中的实体对象的 DTO。当前业务逻辑存储在实现以下接口IService的 Service 类中

public interface IService<TEntity> {

        IEnumerable<TEntity> Get();
        TEntity GetByID(int id);
        void Insert(TEntity entity);
    }

该服务类通过 ctor 参数获取 UnitOfWork 并用于操作。Automapper 还实现了将实体对象转换为 DTO,反之亦然。从现在开始,所有上层不再对实体模型感兴趣,只使用 DTO。所以几乎所有的项目(包括 api 和 web )都引用了这个项目。

Common:负责存储常用的库,如日志记录。

WebCore:负责存储 API 或 MVC 等基于 Web 的项目的常用库。还包含基于 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 分开,并为实体再次耦合它们。但我找不到比这更好的方法了。

这是一个很长的问题,但如果您与我分享您的想法以创建更好的架构,我将非常高兴。

4

1 回答 1

30

问题 1:假设您有一个复杂的业务领域和重要的业务逻辑,值得付出努力,因为您必须将您的领域层与基础设施问题隔离开来。然而,情况往往并非如此。如果您主要只是将数据从数据库移动到 UI 并再次返回,那么这就是过度工程,您应该寻求移动部件更少的东西。

问题 2:您有多少不同的领域模型(使用不同的通用语言)?一?二?三?对于每个模型,尽可能将其与其他模型和基础设施问题隔离开来。

Eric Evans 将有界上下文定义为主要是语言边界(引自他的书中):

有界上下文界定了特定模型的适用性,以便团队成员对什么必须一致以及它与其他上下文的关系有清晰的共同理解。在该 CONTEXT 中,努力保持模型在逻辑上的统一,但不要担心超出这些界限的适用性。在其他 CONTEXTS 中,其他模型适用,但在术语、概念和规则以及无处不在的语言方言方面存在差异。

DBContext 可能会为您指明正确的方向,但请记住,它是基础设施工件,而不是域概念。它“代表了工作单元和存储库模式的组合,使您能够查询数据库并将更改组合在一起,然后将这些更改作为一个单元写回存储区。”_(来自MSDN Docs)。

DDD 是关于领域建模:使用模型来解决复杂业务领域中的困难业务问题。从技术考虑中推导出模型边界感觉就像在摇尾巴一样。从概念上定义模型的边界,然后相应地调整您的技术基础设施。

问题 3: DTO 可能是强制执行上下文边界的好方法,例如对于 API。然后,该 API 可以作为其他模型的反腐败层。人们通常将它们用于 UI 的原因是避免将 UI 概念引入领域模型。

不要寻求完美的架构。并意识到“最佳实践”实际上只是基于特定情况的指导方针。遵循其他更有经验的人制定的指导方针,并了解您的情况可能略有不同。当您发现摩擦时,使用您的期望重构您的设计决策。例如,如果稍后您发现 UI 的 DTO 太过分了,则将其删除。尽可能简化。

于 2013-02-15T14:21:51.020 回答