为我的MVC应用程序创建服务层?


82

据我了解,MVC通过作为控制器的“胶水”将类定义(模型)与表示(视图)分开。控制器应负有单一责任,因此是可测试的。ViewModel用于将来自多个实体的数据汇总在一起,并“按摩”来自视图的控制器的数据。

似乎业务逻辑并没有真正的位置...所以我认为适合服务的另一层是合适的。我只是不确定在哪里放置此层,或如何构建服务-它应该是一个包含大量功能的称为“服务”的类吗?我对MVC有点陌生,因此任何阅读材料,样本或常规的新手技巧都很棒。

Answers:


126

开发ASP.NET MVC应用程序时,通常使用服务层。它类似于Martin Fowler在企业应用程序体系结构模式中讨论的服务层模式。它封装了您的业务逻辑,并使控制器变薄。基本上,控制器使用服务层来获取域模型,然后将其转换为视图模型。我还使用工作单元设计模式来处理事务,并使用存储库设计模式来封装数据访问层,以简化单元测试并能够轻松换出ORM。该图显示了我在MVC应用程序中使用的典型层。

MVC架构

在此图中,服务层被标记为“应用程序或域层”,因为当您使用术语“服务层”时,我发现人们会感到困惑。他们倾向于认为这是一个Web服务。实际上,它是可以由您喜欢的Web服务技术(例如ASP.NET Web API或WCF)以及控制器使用的程序集。

至于命名约定,我通常使用描述服务后域的名称。例如,如果我有一个处理用户成员资格的服务层,那么我将拥有一个名为MembershipService的类,该类具有控制器和Web服务查询和操纵成员资格域所需的所有方法。请注意,同一应用程序中可能有多个域,因此您可以具有多个服务层。我的意思是,您不必拥有一个照顾整个应用程序的整体服务。


7
有没有很好的例子可以实现这种方法?
Animesh 2013年

@Animesh您只需要在网络中使用示例,DAL的EF + Code First或POCO模板,用于生成存储库和UnitOfWork的T4Scaffolding,服务就可以在DAL和POCO封装业务逻辑之间进行协调。然后,ASP.NET MVC控制器或仅调用服务层并显示结果的ASP.NET MVC控制器(ASP.NET MVC)或将其公开给其他客户端(ASP.NET WebApi)
riadh gomri

2
资源库和UoW是不必要的,不是吗?至少在您的示例中,当您只需要使用一种数据库技术时(而不是DDD)。这就是EF本身已经实现UoW和存储库模式的原因。
krypru

1
我不喜欢这里,因为我喜欢示例和图形,但是许多在线教程不必要地使用Repository Pattern。之所以抽象,是因为它们可以毫无益处地进行抽象,只是可以使用接口。
约翰尼

太棒了!!! 谢谢@kevin Junghans,您的回答确实帮助我构建了复杂的Web应用程序。一个简短的问题,在开发基于微服务的Web应用程序时,我们需要实现Service类还是仅由​​MVC类来完成这项工作。
codemilan

28

我的建议是创建一个单独的类,称为“服务”。将它们放在不同的类库(或名称空间)项目中,并使它们独立于MVC框架基础结构。我建议也使用某种依赖注入(最好是构造函数注入)。然后您的服务类可能如下所示:

 public class MyService : IMyService
 {
     IFirstDependency _firstService;
     ISecondDependency _secondService;

     public MyService(IFirstDependency firstService, ISecondDependency secondService)
     {
     }

     public Result DoStuf(InputDTO)
     {
         // some important logic         
     }
 }

然后,您可以从控制器使用这些服务。看看这里为完整的例子。

根据存储库-我的建议是,如果您要使用一些现代的ORM(NHibernate,EntityFramework),请不要使用它们,因为您的业务逻辑将被封装在服务层中,而您的数据库将已经被ORM框架封装。


4
我认为跳过存储库部分并转到ORM的问题在于,您的服务类将直接获取ORM上下文,这意味着服务中的所有这些类都将有权访问您拉入上下文的所有表,而不是每个服务。类只使用所需的表。您可以通过将DbSet传递到每个类的ctor中并使用DI解决该问题来避免这种情况,但是您可能会遇到问题吗?
user441521


10

引用“业务逻辑应该在服务中,而不是模型中”吗?

在MVP / MVC / MVVM / MV *体系结构中,根本不存在服务。或者,如果确实如此,则该术语用于指代可以注入到控制器或视图模型中的任何通用对象。业务逻辑在您的模型中。如果要创建“服务对象”来编排复杂的操作,则可以将其视为实现细节。遗憾的是,很多人都这样实现MVC,但由于模型本身不执行任何操作,因此它被视为反模式(贫血域模型),它只是UI的一堆属性。

有些人错误地认为采用100线控制器方法并将其全部推入服务可以使体系结构更好。确实没有;它所做的只是添加另一个可能是不必要的间接层。实际上,控制器仍在进行工作,只是通过一个名称不正确的“ helper”对象进行的。我强烈推荐Jimmy Bogard的Wicked Domain Models演示,作为一个清晰的示例,说明如何将贫血的领域模型转变为有用的模型。它涉及仔细检查您要公开的模型以及在业务环境中实际上有效的操作。


这是最好的答案。被选中的人说将业务逻辑放在要在控制器中使用的服务上,但是业务逻辑应该在模型上。
Mateus Felipe,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.