【问题标题】:Architecture for MVC web project / usage of different types of modelMVC web 项目的架构/不同类型模型的使用
【发布时间】:2012-02-29 07:42:48
【问题描述】:

我正在构建一个当前有 3 个程序集的项目:

  • 用户界面
  • 核心(服务和模型、实用程序)
  • 存储库 (Linq2SQL)

依赖是

  • UI -> 核心
  • 核心 -> 存储库。

我希望服务和模型位于它们自己的程序集中,并最终得到围绕模型构建的东西,即:

  • UI ->模型、服务
  • 服务 -> 模型、存储库
  • 存储库 -> 模型
  • 型号

我正在构建的系统基本上是一个网站 CMS,因此我将有一个网页模型 (PageModel),其中包含一组子网页。 PageModel 可以调用服务 (PageService) 中的方法来填充其子页面,但在新设计中这是不可能的,因为 Models 程序集必然对服务程序集一无所知。

我已经考虑了洋葱架构中的一些想法(即依赖注入)来解决这个问题,但似乎可以使用更优雅/更明显的解决方案。

需要再引入一层Model吗?查看模型?我认为我所说的模型是领域模型......我很可能错了!那么服务会是域服务吗?

所以我的解决方案是:

  • UI -> 服务、视图模型、模型
  • ViewModels -> 服务、模型
  • 服务 -> 存储库、模型
  • 存储库 -> 模型
  • 型号

在这个例子中,我想我的 PageViewModel 会扩展 PageModel 并使用 PageService 来获取它的子页面..

任何建议表示赞赏。还有关于这些模型层通常被称为什么的任何指针?我在这里谈论的是 DTO 模型而不是域模型吗?域模型而不是视图模型?看来我提议使用视图模型的目的并不是真正的视图模型的工作..

谢谢

编辑:

我最初没有提到的一点是,我的领域模型不是您在大多数教程中看到的单个数据库实体的基本翻译。域模型可以包含来自多个相关数据库表的数据字段。

那么是否值得拥有一组模型来纯粹封装域中的数据 - 没有任何方法/属性来获取相关对象或将对象保存回数据库等? - 数据传输对象。

通过查看几个潦草的图表,这意味着在域层中有一组映射器(这似乎是错误的......)将 DTO 模型转换为域模型并返回。该项目将围绕 DTO 模型而不是域模型构建,但考虑到 DTO 封装的内容,我认为这不是问题。

对于任何感兴趣的人,建议的依赖结构如下所示:

  • UI -> 服务、领域模型
  • 服务 -> 存储库、域模型、DTO 模型
  • 域模型 -> 存储库、DTO 模型
  • 映射器 -> 领域模型、DTO 模型
  • 存储库 -> DTO 模型
  • DTO 模型(无依赖关系)

有点乱!而这一切只是因为我希望我的 PageModel 能够获取它自己的子 PageModels.. 看起来尝试依赖注入可能不是一个糟糕的计划。

感谢回复的人。你给了我很多思考。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-3


    【解决方案1】:

    您可以使用洋葱架构很好地完成此任务。 例如: UI、域、数据访问、服务

    用户界面 服务 数据访问 域(也包含视图模型)

    UI 可以访问任何一个。 服务,只有数据访问和域。 数据访问 - 仅限域。

    我的存储库接口在域项目中,它们在数据访问项目中实现。 我还在域项目中保留了其他接口(IContext、IUnitOfWork 等),因此我有一个中心位置,并且不会在项目之间传播太多接口。

    如果您认为合适,DTO 将仅用于层之间的传输。我没有理由不能从数据层向上传递域模型,有些人选择在这里只使用 DTO。我将在 UI 层(前 MVC 控制器)映射到 ViewModel,因为我可以利用 AoP 为我做这件事([AutoMap()] 属性)

    请记住,您的模型根本不应包含任何持久性逻辑。

    【讨论】:

    • 谢谢亚当。将存储库接口放在域中似乎是一种使所有内容都以域为中心的巧妙方法。在持久化点上,我的领域模型有方便的 Save() 方法,只需调用相关存储库中的 Save() 方法。你会认为这是持久性逻辑,因此是不好的做法吗?
    • 是的,他们应该对此一无所知。将实体传递到您的存储库,让它成为处理所有事情的唯一地方。然后这很好地适应了工作单元模式,因为可以重构存储库以现在将其实际保存到集合中,并且工作单元实现在一个事务中将该集合保存到数据库中。您的服务,而不是在模型上调用 Save(),而是只知道调用存储库实现,它应该被注入到您的控制器或存储库中。这非常适合测试/模拟/等。
    【解决方案2】:

    我认为任何“现实世界”应用程序以不同于屏幕上显示的方式存储数据是非常典型的。我认为您走在正确的轨道上,拥有 2 个单独的“模型”。我通常最终会打电话给他们:

    • ViewModels - 映射到屏幕上显示的内容,视图想要的内容。
    • DataModels - 映射到数据库,持久层 (ORM) 想要什么。

    有时DataModels 被称为Entities,尤其是在将实体框架作为数据访问层或Data Transfer Objects (DTO) 时。

    通常也有一些“转换器”可以从视图映射到数据模型,或者有时可以使用 AutoMapper。

    当然,如果您显示的内容与您的数据结构足够接近,那么将所有持久性/数据模型传递给视图并没有什么坏处,但我也喜欢将它们分开。

    【讨论】:

    • 谢谢。我开始怀疑 DTO 模型。我的模型不一定是来自单个数据库表的简单映射。不过,我可能必须回答我自己的帖子才能正确解释..
    【解决方案3】:

    我已经考虑了洋葱架构中的一些想法(即依赖注入)来解决这个问题,但似乎可以使用更优雅/更明显的解决方案。

    一旦你掌握了正确使用依赖注入的窍门,它确实是一个非常优雅/明显的解决方案。

    我建议这样的依赖结构:

    • 用户界面
      • 控制器 -> 服务、模型、视图模型
      • 视图 -> 视图模型
      • ViewModel(无依赖关系)
    • 服务 -> 存储库、模型
    • 存储库 -> 模型
    • 型号

    这与您之前的非常接近,但是您的 ViewModel 是您的 UI 项目的一部分,并且完全没有依赖关系。它们应该只是简单的类,代表您想向用户显示的内容。

    控制器的工作是:

    • 调用服务以获取模型,
    • 将模型转换为 ViewModel,并
    • 调用查看代码

    视图不应要求任何 ViewModel 未提供的信息。

    【讨论】:

    • 谢谢。我认为依赖注入开始看起来像是要走的路。该项目已经相当复杂了(按照我的标准..),实施 DI 可能是一个相当大的挑战..
    • @Giles:DI 倾向于让你遵循良好的设计模式。由于您一直没有使用它,因此尝试使您的代码遵循它应该一直使用的模式可能会有些痛苦。但如果你做得对,DI 实际上应该可以帮助你简化一些事情。祝你好运。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2013-09-10
    • 2018-02-02
    • 1970-01-01
    • 2014-07-19
    • 2011-07-15
    相关资源
    最近更新 更多