您对以下'generic'代码优先的Onion启发的ASP.NET MVC架构有何看法:
这些层次解释说:
Core - 包含域模型 . 例如这是业务对象及其关系 . 我正在使用Entity Framework来可视化地设计实体及它们之间的关系 . 它让我为数据库生成一个脚本 . 我正在获得自动生成的类似POCO的模型,我可以在下一层(持久性)中自由引用,因为它们很简单(即它们不是特定于数据库的) .
Persistence - 存储库接口和实现 . 基本上是对域模型的CRUD操作 .
BusinessServices - 存储库周围的业务层 . 所有业务逻辑都应该在这里(例如 GetLargestTeam()
等) . 使用CRUD操作组成返回对象或获取/过滤/存储数据 . 应包含所有业务规则和验证 .
Web (or any other UI) - 在这种特殊情况下,它是一个MVC应用程序,但这个项目背后的想法是提供UI,由业务服务提供的驱动 . UI项目使用Business层,无法直接访问Repository . MVC项目有自己的View模型,这些模型特定于每个View情境 . 我不是试图强制它域模型 .
So the references go like this: UI - >业务服务 - >存储库 - >核心对象
What I like about it:
-
我可以设计我的对象,而不是手动编码 . 我正在获得代码生成的Model对象 .
-
UI由业务层驱动/强制执行 . 可以针对同一商业模型对不同的UI应用程序进行编码 .
Mixed feelings about:
-
很好,我们有一个可插拔的存储库实现,但是你有多少次真正拥有相同持久性接口的不同实现?
-
UI也是如此 - 我们具有针对相同业务规则实现不同UI应用程序的技术能力,但是当我们可以简单地呈现不同的视图(移动,桌面等)时,为什么我们会这样做呢?
-
我不确定UI是否应该只通过View模型与业务层进行通信,或者我是否应该使用域模型来传输数据,就像我现在一样 . 为了显示,我使用的是视图模型,但是对于数据传输,我使用的是Domain模型 . 错误?
What I don't like:
-
核心项目现在在每个其他项目中引用 - 因为我想/必须访问域模型 . 在传统的Onion架构中,核心仅由下一层引用 .
-
DbContext在.Core项目中实现,因为它是由实体框架生成的,位于.edmx所在的位置 . 我实际上想要使用.EDMX进行可视化模型设计,但我觉得DbContext属于Persistence层,位于特定于数据库的存储库实现中 .
作为一个最后的问题 - 什么是一个没有过度设计的好建筑(比如一个完整的洋葱,我们有注射,服务定位器等),但同时提供一些合理的灵活性,在你想要的地方现实需要吗?
谢谢
4 回答
哇,这里有很多话要说! ;-)
首先,我们来谈谈整体架构 .
我在这里看到的是它并不是真正的洋葱架构 . 您忘记了最外层,即“依赖性解析”层 . 在Onion架构中,由此层将Core接口连接到Infrastructure实现(Persistence项目应该驻留在哪里) .
以下是您应该在洋葱应用程序中找到的内容的简要说明 . 核心层中的内容是业务所特有的:域模型,业务工作流......此层将所有技术实现需求定义为接口(即:存储库的接口,日志记录接口,会话接口......) . Core层不能引用任何外部库,也没有特定于技术的代码 . 第二层是Infrastructure层 . 该层提供非业务Core接口的实现 . 这是您调用数据库,Web服务的地方......您可以引用所需的任何外部库来提供实现,根据需要部署尽可能多的块包:-) . 第三层是你的用户界面,你知道要放在那里;-)和最新的层,这是我上面谈到的依赖性解决方案 .
层之间的依赖方向朝向中心 .
以下是它的外观:
现在的问题是:如何适应你的想法已经在洋葱架构中编码 .
是的,这是正确的地方!
那么,您需要将接口与实现分开 . 需要将接口移动到Core中,并且需要将实现移动到Infrastructure文件夹中(您可以将此项目称为Persistence) .
这需要在Core中移动,但是你不应该在这里使用存储库实现,只需操作接口!
很酷:-)
您需要添加一个“Bootstrapper”项目,只需看看here即可了解如何继续 .
关于你的复杂情绪:
我不会讨论是否需要存储库,你会在stackoverflow上找到很多答案 .
在我的ViewModel项目中,我有一个名为“Builder”的文件夹 . 由我的构建者来讨论我的业务服务接口以获取数据 . 构建器将接收Core.Domain对象的列表,并将它们映射到正确的ViewModel .
关于你不喜欢的东西:
错! :-)每一层都需要Core才能访问那里定义的所有接口 .
再一次,只要编辑与EDMX相关的T4模板非常容易,就不会有问题 . 您只需要更改生成的文件的路径,您就可以在Infrastructure层中使用EDMX,在Core.Domain项目中使用POCO .
希望这可以帮助!
我将我的服务注入我的控制器 . 这些服务返回位于Core的DTO . 您拥有的模型看起来不错,我不使用存储库模式,但很多人都这样做 . 我很难在这种类型的架构中使用EF,这就是我选择使用Nhibernate的原因 .
你最后一个问题的可能答案 .
核心
DOMAIN
DI
基础设施
演讲
服务
在我看来:
"the layers above can use any layer beneath them"作者:Jeffrey Palermo http://jeffreypalermo.com/blog/the-onion-architecture-part-3/
另一方面,我使用Onion Architecture创建了一个简单的应用程序来显示层之间的依赖关系以及它应该如何实现 . http://www.jaider.net/posts/935-onion-architecture-in-action-get-started/
你所做的看起来相当不错,基本上是我看到的两个标准架构之一 .
可插拔通常被吹捧为好的设计,但我从来没有见过一个团队换掉一些其他东西的主要实现 . 他们只是修改现有的东西 . 恕我直言“可插拔性”仅适用于模拟自动化单元测试的组件 .
我认为视图模型是一个UI(MVC Web)问题,如果您添加了不同类型的UI,例如它可能不需要视图模型或可能需要不同的东西 . 因此,我认为业务层应返回域实体,并允许它们映射到UI层中的视图模型 .
正如其他人所说,这是很正常的 . 通常一切都最终依赖于域 .
我认为这是实体框架的结果 . 如果您在“Code First”模式下使用它,您实际上可以 - 并且通常会 - 在Persistance层中使用Domain(表示为POCO类)的上下文和存储库在您所谓的Core中 .
正如我上面提到的那样,除了允许进行自动化单元测试外,我不担心需要更换东西 . 除非有特定的要求,否则你很有可能 .
祝好运!