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

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

到目前为止,我所见过的所有ASP.NET MVC演示都将控制器中的存储库访问权限和业务逻辑放在一起。 有些甚至在那里也进行validation。 这导致相当大,臃肿的控制器。 这真的是使用MVC框架的方式吗? 看来,这只是最终会有很多重复的代码和逻辑分布在不同的控制器。

业务逻辑应该真的在模型中。 你应该瞄准胖的模型,瘦的控制器。

例如,而不是有:

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); } } 

或类似的东西。

我喜欢Microsoft Patterns&Practices提供的图表。 我相信“一张图片胜过千言万语”的谚语。

该图显示了MVC和业务服务层的体系结构

这是一个有趣的问题。

我认为有趣的是,大量的样本MVC应用程序实际上并没有遵循MVC范式,从而将“业务逻辑”完全置于模型中。 Martin Fowler指出,MVC不是“四人帮”意义上的模式。 相反,程序员必须添加模式才能创造超出玩具应用程序的范例。

所以,简单的答案是,“业务逻辑”实际上不应该存在于控制器中,因为控制器具有处理视图和用户交互的附加function,并且我们希望仅以一个目的创build对象。

更长的答案是,在将逻辑从控制器移到模型之前,需要对模型层的devise进行一些思考。 也许你可以使用REST处理所有的应用程序逻辑,在这种情况下,模型的devise应该相当清晰。 如果不是,你应该知道你将使用什么方法来防止模型变得臃肿。

你可以通过Stephen Walther查看这个令人敬畏的教程,其中显示了使用服务层validation 。

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

业务逻辑不应包含在控制器中。 控制者应该尽可能地瘦,理想的是按照模式:

  1. find域实体
  2. 在域名实体上行事
  3. 准备查看/返回结果的数据

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

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

什么是模型? 现在这是一个很好的问题。 请参阅微软模式和实践文章 (荣誉AlejandroR优秀的发现)。 在这里有三种types的模型:

  • 查看模型 :这只是一个数据包,使用最less的(如果有的话)逻辑将数据传递到视图,包含基本的字段validation。
  • 领域模型 :具有业务逻辑的胖模型,对单个或多个数据实体(即处于给定状态的实体A而不是对实体B的行动)
  • 数据模型 :存储感知模型,包含在单个实体中的逻辑仅与该实体相关(即,如果字段a然后是字段b)

当然,MVC是一个不同品种的范例。 我在这里描述的只是MVC占据顶层, 在维基百科上提供这篇文章

今天,MVC和类似的模型 – 视图 – 演示者(MVP)是分离关注的devise模式,专门应用于更大系统的表示层。 在简单的情况下,MVC可能代表系统的主要devise,直接进入数据库; 然而,在大多数情况下,MVC中的Controller和Model对服务或数据层/层都有一个松散的依赖关系。 这是关于客户端 – 服务器体系结构的

如果你使用dependency injection器,你的业务逻辑将转到他们,因此你将得到干净整洁的控制器。