【问题标题】:Creating a Service Layer for my MVC application?为我的 MVC 应用程序创建服务层?
【发布时间】:2013-02-15 03:33:10
【问题描述】:

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

似乎业务逻辑并没有真正占有一席之地......所以我认为另一个服务层是合适的。我只是不确定在哪里放置这一层,或者如何构建服务 - 它应该是一个名为“服务”的类,其中包含一堆功能吗?我对 MVC 有点陌生,所以任何阅读材料、示例或一般的新手提示都会很棒。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4


    【解决方案1】:

    在开发 ASP.NET MVC 应用程序时,我通常使用服务层。它类似于 Martin Fowler 在企业应用架构模式中讨论的Service Layer Pattern。它封装了您的业务逻辑并使控制器非常薄。基本上,控制器使用服务层来获取域模型,然后将其转换为视图模型。我还使用Unit of Work Design Pattern 处理事务并使用Repository Design Pattern 封装数据访问层,以便于进行单元测试并能够轻松地换出ORM。此图显示了我在 MVC 应用程序中使用的典型层。

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

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

    【讨论】:

    • 有没有一个很好的例子可以实现这种方法?
    • @Animesh 你只需在网络中编写示例,EF + Code First 或用于 DAL 的 POCO 模板,用于生成 Repository 和 UnitOfWork 的 T4Scaffolding,Service 只是 DAL 和封装业务逻辑的 POCO 之间的协调。然后 ASP.NET MVC Controller OR WebApi 只调用服务层并显示结果(ASP.NET MVC)或将其暴露给其他客户端(ASP.NET WebApi)
    • 存储库和 UoW 是不必要的,不是吗?至少在您的示例中,当您必须仅使用一种数据库技术(而且它不是 DDD)时。这就是 EF 本身已经实现了 UoW 和存储库模式的原因。
    • 这里我不知道,因为我喜欢示例和图形,但是网上很多教程都不必要地使用了存储库模式。它们抽象是因为它们可以抽象而没有任何好处,只是为了使用接口。
    • 太棒了!!!谢谢@kevin Junghans,您的回答确实帮助我构建了复杂的 Web 应用程序。一个简短的问题,在开发基于微服务的 Web 应用程序时,我们是否需要实现服务类或简单的 MVC 类来完成这项工作。
    【解决方案2】:

    引用 “Business logic should be in a service, not in a model”?:

    在 MVP/MVC/MVVM/MV* 架构中,根本不存在服务。或者如果他们这样做,该术语用于指代任何可以注入控制器或视图模型的通用对象。业务逻辑在您的模型中。如果你想创建“服务对象”来编排复杂的操作,这被视为一个实现细节。可悲的是,很多人都这样实现 MVC,但它被认为是一种反模式(贫血域模型),因为模型本身什么都不做,它只是 UI 的一堆属性。

    有些人错误地认为采用 100 行控制器方法并将其全部放入服务中会以某种方式获得更好的架构。真的没有;它所做的只是添加另一个可能不必要的间接层。实际上,控制器仍在做这项工作,它只是通过一个名称不佳的“帮助器”对象来做。我强烈推荐 Jimmy Bogard 的 Wicked Domain Models 演示文稿,这是一个关于如何将贫血域模型变成有用模型的清晰示例。它涉及仔细检查您公开的模型以及哪些操作在业务环境中实际有效。

    【讨论】:

    • 这是最好的答案。选中的说把业务逻辑放在服务上,用在控制器上,但业务逻辑应该放在模型上。
    【解决方案3】:

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

     public class MyService : IMyService
     {
         IFirstDependency _firstService;
         ISecondDependency _secondService;
    
         public MyService(IFirstDependency firstService, ISecondDependency secondService)
         {
         }
    
         public Result DoStuf(InputDTO)
         {
             // some important logic         
         }
     }
    

    然后您从控制器中使用这些服务。 查看here 以获取完整示例。

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

    【讨论】:

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

    查看来自 MSDN 最佳实践的 article

    文章中应用的源码可以在here找到。

    【讨论】:

      【解决方案5】:

      【讨论】:

      • 它不仅仅是存储库模式。服务是关于数据访问,但不完全是恕我直言。
      猜你喜欢
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 2013-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多