服务层应该返回MVC应用程序的视图模型吗?

erg*_*g39 61 asp.net-mvc service-layer asp.net-mvc-viewmodel

假设您有一个ASP.NET MVC项目并且正在使用服务层,例如在asp.net站点上的这个联系管理器教程中:http: //www.asp.net/mvc/tutorials/iteration-4-make-的应用程序,松散耦合-CS

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

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }
Run Code Online (Sandbox Code Playgroud)

如果你想要一个IEnumerable,它应该进入服务层,还是在其他地方是"正确"的地方?

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

cap*_*tom 48

一般来说,没有.

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

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

  • 在大多数情况下,应该"服务"消耗`ViewModels`还是应该在将Post数据传递给服务之前将它映射到`Controller`中的相应实体? (3认同)

duf*_*ymo 25

不,我不这么认为.服务应该只关心问题域,而不是关注呈现结果的视图.返回值应以域对象而非视图的形式表示.


Blu*_*uds 22

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

但是当你开始使用Entity Framework,MVC,Repository等实现它时,你会意识到其他的东西.

有人必须使用ViewModels(最后提到的DTO)映射实体/数据库模型.这应该在[A] UI层(由Controller)或[B]服务层中完成吗?

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

再次,让我们使用选项A,将ViewModel放在UI层(以及Service层中的实体模型)中.

如果服务层需要映射到ViewModel,则服务层需要访问UI层中的ViewModel.哪个图书馆/项目?Viewmodel应位于UI层中的单独项目中,此项目需要由Service Layer引用.如果ViewModel不在一个单独的项目中,那么就有循环引用,所以没有去.让Service层访问UI层看起来很尴尬,但我们仍然可以应对它.

但是,如果有另一个UI应用程序使用此服务怎么办?如果有移动应用程序怎么办?ViewModel有多么不同?服务应该访问相同的视图模型项目吗?是否所有UI项目都可以访问相同的ViewModel项目,或者他们有自己的项目?

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

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

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

[现在这个讨论即将进行一次有趣的转折...:我]

并且不要认为数据注释属性仅适用于UI.如果使用System.ComponentModel.DataAnnotations.dll限制验证,则相同的ViewModel也可用于前端和后端验证(从而删除UI驻留-ViewModel-copy-of-DTO).此外,属性也可用于实体模型.例如:使用.tt,可以使用验证属性自动生成实体框架数据模型,以便在发送到后端之前执行一些DB验证,例如max-length.另一个优点是,如果DB中的后端验证发生变化,那么.tt(读取DB特定内容并为实体类创建属性)将自动选择它.这可能会迫使UI验证单元测试失败,这是一个很大的优点(因此我们可以纠正它并通知所有UI /消费者,而不是意外忘记和失败).是的,讨论正朝着良好的框架设计方向发展.正如您所看到的那样,它们都是相关的:分层验证,单元测试策略,缓存策略等.

虽然与问题没有直接关系.'ViewModelFaçade'中提到的必须观看频道9链接也值得探索.它在视频中以11分49秒开始.因为一旦上面给出的当前问题得到解决,这将是下一步/思考:"如何组织ViewModels?"

同样在您的示例中"_repository.ListContacts()"从存储库返回ViewModel.这不是一种成熟的方式.存储库应提供实体模型或数据库模型.这将转换为视图模型,这是服务层返回的视图模型.


Aar*_*ght 5

我想这取决于你认为的"服务".我从来没有真正喜欢单一课程中的服务这个术语; 这是非常模糊的,并没有告诉你很多关于班级的实际目的.

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

只是不要混合概念.如果您的服务处理视图模型,那么它应该是一个表示服务,并且可以在实际模型之上进行分层,而不是直接触及数据库或任何业务逻辑.


小智 5

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

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

尽管我仍然不相信这是最佳或正确的解决方案-但最终导致一些激烈的讨论,即“我们是否只是在DTO中添加X以满足视图的需求?”