MVC应用程序在哪里适合“业务逻辑层”?


86

首先,在有人大声疾呼之前,我很难用一个简单的标题来概括它。另一个标题可能是“域模型和MVC模型之间有什么区别?” 或“什么是模型?”

从概念上讲,我将模型理解为视图和控制器使用的数据。除此之外,对于构成模型的原因似乎有很多不同的意见。什么是领域模型,应用程序模型,视图模型,服务模型等。

例如,在我最近询问存储库模式的问题中,有人告诉我空白是存储库是模型的一部分。但是,我还读过其他意见,认为该模型应与持久性模型和业务逻辑层分开。毕竟,存储库模式是否不应该将具体的持久性方法与模型分离?其他人说,域模型和MVC模型之间是有区别的。

让我们举一个简单的例子。MVC默认项目中包含的AccountController。我已经读过一些意见,认为其中包含的帐户代码设计不佳,违反了SRP等。如果要为MVC应用程序设计“适当的”成员资格模型,那将是什么?

您如何将ASP.NET服务(成员资格提供程序,角色提供程序等)与模型分开?还是你会吗?

从我的角度来看,模型应该是“纯”的,也许带有验证逻辑..但是应该与业务规则(除了验证)分开。例如,假设您有一条业务规则,该规则规定在创建新帐户时必须向某人发送电子邮件。在我看来,这并不真正属于模型。那么它属于哪儿呢?

有人在乎这个问题吗?


1
因此,您应该问四个独立的问题。
约翰·法瑞尔

3
关键字是“几乎”。这确实是一个相同的问题,可能使用子问题来说明主要问题。
Erik Funkenbusch 2010年

3
模型-视图-控制器。是存储库/ BL视图吗?不,是控制器吗?不,还剩下什么:)?它是MVC,不是MSVC,不是MRVC,不是MBLVC。只有三层。因此,存储库是模型的一部分,BL是模型的一部分。您可以进行其他分离,但这是在模型层内部完成的。
LukLed 2010年

3
@ LukeLed,@ bslm-并非如此。MVC没有说控制器或模型不能与其他层交互。
约翰·法瑞尔

3
@LukLed-不同意-MVC只是表示层模式。它对您如何构造其他层(如BLL和DAL)没有影响。
Cory House

Answers:


69

我这样做的方式-我并不是说对与错,是拥有我的视图,然后建立一个适用于我的视图的模型。该模型仅具有与我的视图相关的内容-包括数据注释和验证规则。控制器仅包含用于构建模型的逻辑。我有一个包含所有业务逻辑的服务层。我的控制器调用我的服务层。除此之外,还有我的存储库层。

我的域对象是单独存放的(实际上是在自己的项目中)。他们有自己的数据注释和验证规则。我的存储库会先验证域中的对象,然后再将其保存到数据库中。因为我域中的每个对象都从内置了验证的基类继承,所以我的存储库是通用的并验证所有内容(并要求它从基类继承)。

您可能会认为拥有两组模型是代码的重复,并且在一定程度上是重复的。但是,在某些完全合理的实例中,域对象不适用于该视图。

一个很好的例子是使用信用卡-处理付款时我必须要求提供cvv,但我不能存储cvv(这样做会被罚款50,000美元)。但是,我也希望您能够编辑您的信用卡-地址,姓名或有效期的更改。但是您在编辑时不会给我这个号码或cvv,我当然也不会在页面上以纯文本形式显示您的信用卡号。我的域具有保存新信用卡所需的这些值,因为您将它们交给了我,但我的编辑模型甚至不包括卡号或cvv。

如此多的层的另一个好处是,如果正确地进行了架构,则可以使用structuremap或另一个IoC容器并交换部分,而不会对应用程序产生不利影响。

我认为,控制器代码应仅针对视图。显示,隐藏等。服务层应包含应用程序的业务逻辑。我喜欢将所有内容都放在一个地方,因此很容易更改或调整业务规则。信息库层应该相对笨拙-没有业务逻辑,仅查询数据并返回域对象。通过将视图模型与域模型分开,您可以在定制验证规则方面拥有更大的灵活性。这也意味着您不必将每段数据都转储到隐藏字段中的视图中,并在客户端和服务器之间来回推送(或在后端重建)。

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

尽管所有内容似乎都散布了起来,但它的目的是通过这种方式进行架构。完美吗?并不是的。但是我确实更喜欢它过去的一些设计,即从控制器调用存储库,并在控制器,存储库和模型中混合业务逻辑。


就像我在企业MVC应用程序中拥有的一面镜子。N层架构。MVC应用程序仅与N层区域中的业务对象和服务进行交互。
Ed DeGagne 2013年

这里大致相同。单独的项目用于定义,模型,视图模型,DAL等。唯一的区别是我的DAL包含逻辑,用于整理Web数据以优化报表或自定义客户视图的复杂数据分配。现在,我避免使用Web场和Azure云将内容保存在应用程序缓存中以用于查找表等。
罗伯特·阿赫曼

1
@Josh,如果您可以显示示例项目的屏幕截图,这会有所帮助吗?
shaijut

@Josh如果您的项目没有数据库怎么办。它与服务引用进行交互。所有域类和方法都来自这些引用。这种情况适合分层结构吗?
user6395764 '18

17

我也常常想知道MVC元素到底如何适合传统的Web应用程序结构,在该结构中您具有视图(页面),控制器,服务和数据对象(模型)。如您所说,有很多版本。

我认为,由于上面提到的,被广泛接受的体系结构(使用“贫血域模型”(被称为)-反模式)而引起的混乱是存在的。我不会详细介绍贫血数据模型的“反模式”(您可以在这里解释我的工作(基于Java,但与任何语言都相关))。简而言之,这意味着我们的模型仅保存数据,而业务逻辑放置在服务/管理器中。

但是,让我们假设我们拥有域驱动的体系结构,并且我们的域对象就是预期的样子-具有状态和业务逻辑。在这种领域驱动的观点中,事情就已经到位:

  • 视图是UI
  • 控制器收集UI的输入,调用模型上的方法,然后将响应发送回UI
  • 该模型是我们的业务组件-保存数据,但也具有业务逻辑。

我想这回答了您的主要问题。当我们添加更多的层(例如存储库层)时,事情变得复杂。通常建议应通过放置在模型中的业务逻辑来调用它(因此,每个域对象都有对存储库的引用)。在我链接的我的文章中,我认为这不是最佳实践。而事实上,拥有服务层并不是一件坏事。顺便说一句,域驱动的设计并不排除服务层,而是应该是“瘦”的,并且只能协调域对象(因此那里没有业务逻辑)。

对于广泛采用的贫血数据模型范例(无论是好是坏),该模型既是服务层又是您的数据对象。


好点!一句话:服务也有混乱。至少服务可以是应用程序服务和域服务。应用程序服务只是一个薄包装程序,它从存储库等收集信息。域服务提供了业务逻辑,即使用域模型的组合或仅仅是不总是适合域模型的东西。
Artru 2013年

如果您的项目没有数据库怎么办。它与服务引用进行交互。所有域类和方法都来自这些引用。这种情况适合分层结构吗?
user6395764 '18

3

在我看来,

型号-

不应该包含业务逻辑,它应该是可插拔的(类似WCF的场景)。它用于绑定视图,因此它应该具有属性。

商业逻辑 -

它应该放在“域服务层”,它是完全分开的层。另外,将在此处的“应用程序服务”中再增加一层。

App Services与Domain Services层进行对话以应用业务逻辑,然后最后返回模型。

因此,Controller会向Application Service索要Model,流程将如下所示:

    Controller->Application Services(using domain services)->Model

2

MVC模式和Asp.net框架对模型应该是什么没有区别。

MS自己的示例在模型中包括持久性类。您有关模型中成员身份的问题。这取决于。您模型中的类是否归某物所有?谁登录和显示什么数据之间是否存在链接?权限系统中的数据部分是否可过滤?谁最后一次更新或编辑了您域中的对象,而其他人则需要查看它或提供一些后端支持?

电子邮件示例也取决于。您是否熟悉域事件或特别是事件?您是否有单独的服务来发送电子邮件?发送电子邮件的行为是您域的一部分,还是系统范围之外的应用程序级别的关注点?UI是否需要知道是否成功发送了电子邮件?无法发送的电子邮件是否需要重试?发送的电子邮件内容是否需要存储以用于支持或客户服务要求?

这些类型的问题过于笼统和主观,但我正在回答,因此您和每个投票支持您的人都可以理解。

您的需求/时间表/资源全部渗入系统的体系结构。甚至收入模型也会产生影响。您还必须考虑要拍摄的图案。DDD与持久性模型应用程序有很大不同,并且两者之间的所有限制对某些应用程序也有效。您是否正在为测试该应用程序而射击?所有这些都有作用。

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.