83

首先,我看到了很多这样的问题,但背后的推理还不够。如果我的问题不够好并且应该被删除,我会理解的。

例如,我查看了这个,一个 45+ 投票的答案说他建议你将业务逻辑放入模型中,这听起来很合乎逻辑。

但是,我的第一个大型项目是我在控制器中完成了所有 BL,因为我没有质疑这些事情,而是查看了它是如何完成的AccountController,如果你选择带有表单身份验证的 MVC,它是自动添加的。所有的方法看起来都充满了 BL。或者也许这是可以添加的最少代码量而我忽略了一些事情?

youtube上的一个人通过将所有逻辑都放入他的模型中来问我他是否正确,起初我不是!然后我开始想,也许他是对的!?

所以,毕竟,我应该把我的业务逻辑放在哪里?如果它在模型类中,那么在控制器中的方法中应该考虑多少代码是健康的?最多从控制器中的模型调用某些方法然后返回视图的一行?

4

12 回答 12

56

出于几个原因,我更喜欢将域逻辑放入模型中。

  1. 模型中应该没有 UI 代码,因此更容易测试。只要有可能,我喜欢在编写任何 UI 代码之前拥有一个完全工作(意味着完整的测试覆盖)的模型。控制器可以相信模型正在做正确的事情,并且只处理 UI 问题。

  2. 如果你把域逻辑放在一个控制器中,在不同的应用程序之间共享,甚至在不同的控制器之间共享都不是那么容易。

于 2013-09-01T22:07:04.853 回答
45

我喜欢让我的模型保持干净,即只有属性,没有业务逻辑。我一直认为将依赖项注入控制器是件好事,这些依赖项包含我在模型上执行的逻辑。我喜欢尽可能坚持单一职责原则,我发现具有大量方法的模型很快就会变得臃肿。两者各有利弊,注入大量依赖项会产生开销,但允许单独测试并保持类简单,最终您将拥有更精简的控制器。尽管我的逻辑实际上并不作为班级成员存在于我的模型中,但它仍然是业务逻辑。我倾向于没有在控制器中定义业务逻辑,因为像 Httpcontext 这样的模拟东西有点像噩梦并且没有必要。

于 2013-09-01T21:49:07.680 回答
25

业务逻辑属于问题域,属于问题域的一切都进入 MVC 中的模型

控制器应该负责将数据从模型传递到视图,然后从视图传回模型。因此,控制器是用户与之交互的内容与程序如何建模和存储问题状态之间的桥梁。管道,可以这么说。

这里的关键是业务逻辑和管道逻辑之间的区别。在我看来,自动生成的 Account Controller 所做的主要是管道,而不是真正的业务逻辑。请记住,管道逻辑根本不一定很短,因此您不需要强加人为限制(例如“控制器中最多 X 次调用”)。

于 2013-09-01T21:52:43.210 回答
15

围绕这个话题似乎有些混乱。大多数情况下,人们似乎倾向于将 MVC 模式与 N 层架构混淆为非此即彼的情况。现实情况是,这两种方法可以一起使用,但一种不依赖于另一种,也不需要。

N 层架构涉及将应用程序分成多个层。一个简单的例子是将应用程序拆分为表示层、业务逻辑层和数据访问层。

MVC 是一种处理应用程序表示层的设计模式。完全可以按照 MVC 方法设计应用程序,而无需将业务逻辑和数据访问逻辑与表示层分离,从而最终得到单层设计。

结果,如果您遵循 MVC 方法而不将应用程序划分为层,那么您最终会得到模型、视图和控制器,这些模型、视图和控制器将一些业务规则和数据访问逻辑与其余逻辑混合在一起。

根据定义,在 N 层架构中,表示层应该只能够与业务逻辑层通信,因此它应该认为任何 MVC 组件只能与业务逻辑层通信。

如果您正在构建一个不涉及表示的应用程序,因此不涉及表示层,那么您不必担心 MVC 模式。但是,即使不涉及表示层,您仍然可以将应用程序拆分为多个层,从而遵循 N 层设计。

于 2017-03-02T17:17:43.410 回答
13

我的团队在从 webforms (asp.net) 迁移到 mvc 时进行了大量研究并提出了以下结构。在我看来,这与应用程序的大小无关。它是关于保持代码干净和清晰。

DAL项目

AccountsDAL.cs --- > Calls SP or any ORM if ur using any

BLL项目

AccountsBLL.cs ---> Calls DAL

网络项目

Model
    AccountsModel --- > Contains properties And call BLL
Controllers
    IndexController ---> Calls Models and returns View
Views
    Index

控制器应该负责模型和视图之间的数据传递。除此之外,不应该有任何不必要的代码。例如,如果您正在记录它应该在模型级别而不是控制器上完成。

于 2016-01-18T09:56:53.400 回答
10

业务逻辑不应进入您的模型视图或控制器。应该有一个单独的业务逻辑层;该层的唯一目的是处理您的业务逻辑。这更符合SOLID

如果您将业务逻辑放在 MV 或 C 中,您最终会得到难以测试/重用的代码。

将逻辑放在模型中怎么样?

这是一个糟糕的解决方案。

您最终将陷入对象依赖对象 的依赖地狱。在此处输入图像描述

即使您有一个死的简单函数,您仍然必须满足所有依赖项才能调用它。

它还会导致无缘无故地传递不必要未使用的数据。这也可能会影响性能,具体取决于它的糟糕程度。

我还应该提到,单元测试在 a** 中变得很痛苦,因为您必须模拟多个对象才能测试一个简单的功能。

适用的清洁代码原则

  1. 类/函数只需要完成工作所需的东西。
  2. 如果可能,函数应采用 3 个或更少的参数
  3. 智能命名类/函数/变量(遵循微软标准)
  4. 不要将业务逻辑耦合到模型视图或控制器

控制器

在您的控制器中,您应该能够使用依赖注入来注入业务逻辑层。确保您的控制器仅用于将信息路由到业务逻辑层。控制器不应该直接在其中包含业务逻辑。任何验证都需要IValidatable在模型上处理。任何业务逻辑都需要路由到单独的层。

于 2019-09-25T21:39:08.067 回答
8

一般来说,业务逻辑不应该驻留在任何 MVC 播放器中;它只能由您的控制器操作使用。

正如许多人所提到的,最好创建一个库来托管业务逻辑,作为一组与客户端无关的、可重用的组件。

通过这种方式,我们极大地提高了软件的可重用性、兼容性、可扩展性和可测试性。我们还减少了对某些框架功能的依赖,从而更容易迁移到更新/不同的技术。

多年来,将我们的业务逻辑抽象为一个独立的程序集(或多个程序集)对我们很有帮助。然后,我们的业务逻辑几乎可以被任何 .NET 技术(ASP.NET MVC/API/Core、WPF、Win Forms、WCF、UWP、WF、控制台等)使用。

此外,我们喜欢我们的中间层来处理业务规则和验证逻辑,以减少我们对 .NET MVC 框架的依赖。例如,我们避免使用 .NET MVCs 验证助手,而是依赖我们自己的。这是另一个使我们能够轻松使用任何 .NET 技术的业务逻辑的因素。

以这种方式逻辑设计我们的中间层使我们能够轻松地实现这种物理架构:

在此处输入图像描述

它是用Peasy.NET编写的,多年来一直为我们服务。事实上,我们决定开源它。

如果有人对我们的中间层是什么样子感到好奇,这里有一个与客户端无关的业务层示例。它还展示了多个 .NET 客户端(ASP.NET MVC、Web Api 和 WPF)对它的使用。

希望这对某人有帮助!

于 2017-06-10T19:50:06.753 回答
5

我的一般答案是业务逻辑通常分为两类:

面向对象的业务逻辑:被建模为对象(在模型中),通常作为存储库注入。

程序化业务逻辑:进入具有可以注入控制器的接口的服务。

控制器逻辑:控制如何接收命令并将其传递给模型/服务的逻辑,然后将这些结果传递给视图。

控制器不应该有业务逻辑,它是设计模式的一个非常具体的部分,用于控制用户界面如何将输入传递给处理业务逻辑的模型(或服务,如果您的问题本质上是程序性的)。

于 2019-05-30T17:09:45.320 回答
2

我也喜欢保持我的模型干净(参考:@Mark Walsh)。无法重用嵌入在控制器中的逻辑的问题可以通过依赖注入轻松解决,或者,如果您认为其中过多,请通过接口公开您的业务/域逻辑并在控制器中使用外观模式。这样您就可以获得所需的功能,但同时保持控制器和模型的美观和整洁。

于 2014-04-24T19:20:26.447 回答
1

我也希望保持模型清洁。MVC 控制器应仅用于进行调用,并且还应保持清洁。因此,根据其可重用性、敏感性和相关性,可以编写业务逻辑

1.WebApi 控制器:使用webapi 控制器的优点是您可以稍后将这些作为服务公开给其他设备,从而使您的代码可重用。

2. BAL / Common commonent:有些逻辑有特定的用法,不能暴露为api,可以在这个类中推送。

3. 存储库:所有与数据库相关的查询都添加到存储库中。可以有一个通用存储库,它将为每个表实现所有功能(CRUD 操作)或特定存储库。取决于要执行的操作。

于 2015-02-23T08:34:24.063 回答
1

正如 ahanusa 所写,您应该将业务逻辑放入单独的 DLL 或单独的目录中。
我经常在模型和控制器的同一级别使用一个名为 Logics 的目录,在其中放置执行业务逻辑的类。
通过这种方式,我让模型和控制器都清理干净。

于 2018-09-23T10:40:43.627 回答
0

我知道这是一个关于 MVC 的问题,但我认为我给出的示例(Web API)会很有用。

我正在开发我的第一个 Web API,并且我正在重用来自其他应用程序的业务逻辑。具体来说,它来自外部 DLL,因此我的 API 仅用于与 SAP 解决方案“对话”,接收来自 PO 的请求并发送回响应。

我怎样才能将我的逻辑(已经实现)放入我的控制器中?我不需要它。我的控制器只会接收、验证请求并编写响应以发回数据。

我正在使用 ViewModel 类,它们必须拥有一个映射函数,只是为了从 TransferObjects(来自外部 DLL)读取信息并转换为 ViewModel。

我对我的应用程序(在本例中为 Web API)持有业务逻辑感到不舒服,我认为这种方式会失去可重用性。

我将我的业务逻辑视为注入控制器的依赖项。

为了提供可单元测试的解决方案,我对遗留系统进行了大量重构,我必须创建大量接口并在遗留系统中实现一些设计模式才能提供此解决方案。

在我看来,业务层必须是应用程序的一部分,最好是在另一个类库中。因此,您将在应用程序中实现真正的分离概念。

当然,如果您的 CORE(业务)是您的应用程序(API/WebSite),那么业务规则将在您的 MVC 类中实现。但是将来如果你想开发一个新的应用程序并且一些业务规则是相同的,我敢打赌你会遇到很多问题,只是为了在两个应用程序中实现相同的逻辑。

于 2016-12-15T16:40:52.443 回答