ASP.NET MVC-控制器中是否应该存在业务逻辑?


97

几天前,Derik Whitaker发表了一篇文章,达到了我一直以来很好奇的一点:控制器中是否应该存在业务逻辑?

到目前为止,我见过的所有ASP.NET MVC演示都将存储库访问和业务逻辑放在了控制器中。有些人甚至还在那里进行验证。这导致相当大的,肿的控制器。这真的是使用MVC框架的方式吗?看来这最终将导致许多重复的代码和逻辑散布在不同的控制器上。


该文章的链接已失效-web.archive.org/web/20150906064521/http://devlicio.us/blogs/…是archive.org的副本,供其他感兴趣的人使用。
斯图尔特·摩尔

Answers:


75

业务逻辑实际上应该在模型中。您应该针对胖模型,瘦控制器。

例如,与其具有:

public interface IOrderService{
    int CalculateTotal(Order order);
}

我宁愿拥有:

public class Order{
    int CalculateTotal(ITaxService service){...}        
}

这假定税额是由外部服务计算的,并且需要您的模型知道与外部服务的接口。

这将使您的控制器看起来像:

public class OrdersController{
    public OrdersController(ITaxService taxService, IOrdersRepository ordersRepository){...}

    public void Show(int id){
        ViewData["OrderTotal"] = ordersRepository.LoadOrder(id).CalculateTotal(taxService);
    }
}

或类似的东西。


1
那么您是否会将服务注入到控制器中而不是存储库中?在这种情况下,工作单位原则如何发挥作用?
凯文·庞

我写了更多的东西,希望这更有意义。您可能还需要阅读: weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model 即使与Rails有关,它仍然非常适用。
jonnii

我个人将存储库称为服务。
布拉德·威尔逊,

它们绝对是一种服务,但是专门用于数据访问。这只是我使用的约定,不是我特别提倡的约定。
jonnii

1
这将使您的模型与ITaxService紧密结合。如果要在另一个项目或其他dll中重用模型,则必须具有ITaxService实现或引用,否则您的模型将被破坏,从而违反SOLID原则。ITaxService应该具有您的模型的参考。通过这种方式,您可以在不需要ITaxService参考的其他项目中重用模型。
Mehmet Ali Sert


14

这是一个有趣的问题。

我认为很有趣的是,从真正将“业务逻辑”完全置于模型中的意义上讲,大量示例MVC应用程序实际上未能遵循MVC范例。马丁·福勒(Martin Fowler)指出,就“四人帮”而言,MVC并不是一种模式。相反,如果程序员正在创建超出玩具应用程序的内容则必须向其添加模式,这是一种范例。

因此,简短的答案是“业务逻辑”确实不应该存在于控制器中,因为控制器具有处理视图和用户交互的附加功能,并且我们只希望创建一个目的的对象。

更长的答案是,您需要在将逻辑从控制器转移到模型之前,对模型层的设计进行一些思考。也许您可以使用REST处理所有应用程序逻辑,在这种情况下,模型的设计应该非常清晰。如果不是这样,您应该知道将使用什么方法来防止模型过大。


14

您可以查看Stephen Walther撰写的这篇很棒的教程,其中显示了“使用服务层进行验证”

了解如何将验证逻辑从控制器操作中移出并移到单独的服务层中。在本教程中,Stephen Walther解释了如何通过将服务层与控制器层隔离来保持关注点的清晰分离。


2
这是最正确的答案。我个人进一步主张不要将服务公开给控制器,而是选择使用ViewModel概念,例如MVVM模式中发现的概念。设想一下您想编写一个具有桌面界面(例如Windows窗体或WPF)和Web界面的业务应用程序的方案。解决该问题将导致您转向此处建议的“瘦控制器”模式。底线:切勿将业务逻辑放在模型或控制器中,也不要在没有的控制器中放入任何东西。
2015年

9

控制器中不应包含业务逻辑。控制器应该尽可能的瘦,最好遵循模式:

  1. 查找域实体
  2. 对领域实体采取行动
  3. 准备数据以查看/返回结果

另外,控制器可以包含一些应用程序逻辑。

那么我该把业务逻辑放在哪里?在模型中。

什么是型号?现在,这是一个好问题。请参阅“ Microsoft模式和实践”文章(对AlejandroR的出色发现表示赞赏)。这里有三类模型:

  • 视图模型:这只是一个数据包,具有最少的逻辑(如果有的话)将数据从视图传递到视图,并包含基本的字段验证。
  • 域模型:具有业务逻辑的胖模型,对单个或多个数据实体(即,给定状态下的实体A而不是对实体B的操作)进行操作
  • 数据模型:感知存储的模型,单个实体中包含的逻辑仅与该实体有关(即,如果字段a则字段b)

当然,MVC是一个范式,有多种形式。我在这里描述的只是MVC占据顶层,请参阅Wikipedia上的本文。

如今,MVC和类似的模型视图演示者(MVP)是“关注分离”设计模式,这些设计模式仅适用于大型系统的表示层。在简单的场景中,MVC可以代表系统的主要设计,直接进入数据库。但是,在大多数情况下,MVC中的Controller和Model对Service或Data层/层具有宽松的依赖关系。这一切都与客户端-服务器架构有关


-1

如果您使用Dependency Injectors,您的业务逻辑将进入它们,因此您将获得整洁的控制器。

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.