假设您有一个 ASP.NET MVC 项目并且正在使用服务层,例如 asp.net 站点上的联系人管理器教程: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely- Coupled-cs

如果您的视图有视图模型,那么服务层是否是提供每个视图模型的适当位置?例如,在服务层代码示例中有一个方法

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

如果您想要一个 IEnumerable,它应该放在服务层中,还是有其他地方是“正确”的地方?

也许更合适的是,如果与 ContactController 关联的每个视图都有一个单独的视图模型,那么 ContactManagerService 是否应该有一个单独的方法来返回每个视图模型?如果服务层不是合适的位置,那么视图模型对象应该在哪里初始化以供控制器使用?

有帮助吗?

解决方案

一般来说,不会。

视图模型旨在向视图提供信息以及从视图提供信息,并且应该特定于应用程序,而不是一般域。控制器应该协调与存储库、服务(我在这里对服务的定义做出一些假设)等的交互,并处理构建和验证视图模型,并且还包含确定要渲染的视图的逻辑。

通过将视图模型泄漏到“服务”层,您会模糊您的层,现在可能将特定于应用程序和表示的内容与应该关注域级职责的内容混合在一起。

其他提示

不,我不这么认为。服务应该只关心问题域,而不是呈现结果的视图。返回值应该用域对象而不是视图来表示。

根据传统方法或理论,ViewModel 应该是用户界面层的一部分。至少名字是这么说的。

但是,当您开始使用实体框架、MVC、存储库等自行实现它时,您就会意识到一些其他的事情。

必须有人将实体/数据库模型与视图模型(最后提到的 DTO)进行映射。这应该在 [A] UI 层(由控制器)完成,还是在 [B] 服务层完成?

我选择B选项。选项 A 是不行的,因为一个简单的事实是,多个实体模型组合在一起形成一个 ViewModel。我们可能不会将不必要的数据传递到 UI 层,而在选项 B 中,服务可以处理数据并在映射(到 ViewModel)后仅将所需/最小值传递到 UI 层。

再次,让我们选择选项 A,将 ViewModel 放在 UI 层(将实体模型放在 Service 层)。

如果Service层需要映射到ViewModel,那么Service层需要访问UI层的ViewModel。哪个库/项目?Viewmodel应该在UI层的一个单独的项目中,并且这个项目需要被Service层引用。如果 ViewModel 不在单独的项目中,则存在循环引用,因此不进行。让 Service 层访问 UI 层看起来很尴尬,但我们仍然可以应对它。

但是如果有另一个 UI 应用程序使用此服务怎么办?如果有移动应用程序怎么办?ViewModel 有何不同?服务是否应该访问相同的视图模型项目?所有 UI 项目都会访问同一个 ViewModel 项目还是有自己的项目?

经过这些考虑后,我的答案是将 Viewmodel 项目放在服务层中。无论如何,每个 UI 层都必须访问服务层!并且可能有很多他们都可以使用的类似 ViewModel(因此服务层的映射变得更容易)。如今,映射是通过 linq 完成的,这是另一个优点。

最后,还有关于 DTO 的讨论。还有关于 ViewModel 中的数据注释。带有数据注释的ViewModel(Microsoft.Web.Mvc.DataAnnotations.dll)不能驻留在服务层,而是驻留在UI层(但ComponentModel.DataAnnotations.dll可以驻留在服务层)。如果所有项目都在一个解决方案(.sln)中,那么将其放在哪一层并不重要。在企业应用中,每一层都会有自己的解决方案。

所以 DTO 实际上是一个 ViewModel,因为大多数情况下两者之间会有一对一的映射(比如使用 AutoMapper)。同样,DTO 仍然具有 UI(或多个应用程序)所需的逻辑并驻留在服务层中。UI层ViewModel(如果我们使用Microsoft.Web.Mvc.DataAnnotations.dll)只是从DTO复制数据,并添加一些“行为”/属性。

[现在这个讨论即将发生有趣的转变,请阅读...:I]

并且不要认为数据注释属性仅适用于 UI。如果您使用System.componentModel.dataannotations.dll限制验证,则同一ViewModel也可以用于前端和后端验证(因此删除UI-seviending-viewMododel-copy-copy of-of)。此外,属性也可以在实体模型中使用。例如:使用 .tt,可以使用验证属性自动生成实体框架数据模型,以在发送到后端之前执行一些数据库验证,例如最大长度。另一个优点是,如果数据库中的后端验证发生更改,则 .tt(读取数据库详细信息并为实体类创建属性)将自动选择该更改。这也可以迫使 UI 验证单元测试失败,这是一个很大的优点(因此我们可以纠正它并通知所有 UI/消费者,而不是意外忘记和失败)。是的,讨论正在朝着良好的框架设计方向发展。正如你所看到的,它们都是相关的:分层验证、单元测试策略、缓存策略等。

虽然与问题没有直接关系。本文中提到的“ViewModel Façade”必须观看 频道 9 链接 也值得探索。恰好从视频中的 11 分 49 秒开始。因为一旦解决了上面给出的当前问题,这将是下一步/想法:“如何组织 ViewModel?”

另外,在您的示例中,“_repository.ListContacts()”正在从存储库返回 ViewModel。这不是一个成熟的方式。存储库应该提供实体模型或数据库模型。这将转换为视图模型,并且服务层返回的正是该视图模型。

我想这取决于您认为“服务”是什么。我从来没有真正喜欢过这个词 服务 在单个类的上下文中;它非常模糊,并没有告诉你太多关于课程的实际目的。

如果“服务层”是物理层,例如Web服务,那么绝对不是;SOA 上下文中的服务应该公开域/业务操作,而不是数据和表示逻辑。但如果 服务 只是用作进一步封装的抽象概念,我认为按照您描述的方式使用它没有任何问题。

只是不要混淆概念。如果您的服务涉及视图模型,那么它应该是 演示服务 并分层在上面 实际的 模型,从不直接接触数据库或任何业务逻辑。

这在我工作的地方有点“取决于”——我们通常有一个控制器消耗一些服务——然后将返回的 DTO 组合成一个“ViewModel”,然后通过 JSON 结果传递给客户端,或绑定在 Razor 模板中。

事实是,大约 80% 的时间 - DTO 到 ViewModel 的映射是 1-1。我们开始转向“在需要的地方,直接使用 DTO,但是当 DTO 和我们的客户端/视图中需要的内容不匹配时 - 然后我们创建一个 ViewModel 并根据需要在对象之间进行映射”。

尽管我仍然不相信这是最好或正确的解决方案 - 因为它最终导致了一些激烈的讨论:“我们只是在 DTO 中添加 X 来满足视图的需求吗?”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top