.NET MVC项目体系结构/分层


11

在为中型MVC Web应用程序规划体系结构时,如何实现这些层尽可能地分离和易于测试?(基本上遵循最佳实践)假设我首先使用代码作为数据访问权限。

我为定义“业务逻辑”的定义以及与数据层交互的方式感到困惑。以车辆销售应用程序为例,业务逻辑是否是执行诸如计算给定车辆的税阶,比较每加仑英里数统计信息之类的任务的类?至于业务实体(例如汽车,货车,摩托车),我会将它们与DataContext班级一起放在数据层中。

还有什么会构成与业务相对的应用程序逻辑-我正在猜测会话/用户输入验证之类的东西?

因此,例如,汽车管理员可能会返回一个操作/查看结果,其中列出了按类型和最佳mpg过滤的前十名汽车。假设我有一个ICarRepository“ carRepo”注入到我的控制器中(使用存储库模式/ DI),我从一个动作方法参数中过滤了我的汽车var cars = carRepo.getCarsByType("hatchback");

因此,我已使用存储库将数据访问知识排除在控制器之外,现在使用域模型将业务逻辑排除在控制器之外-var result = new MpgCalculator(cars); -假设我需要计算器类,因为它需要执行其他逻辑以计算最佳燃油效率,而不仅仅是从数据库中加载/过滤实体。因此,现在我有了一个供呈现的视图数据集,该数据集使用存储库从数据访问层检索,并且使用特定于域的对象来处理和执行与数据相关的业务相关任务。

我在这里犯错吗?我们仍然需要使用存储库模式吗?或者我可以只对接口进行编码以解耦ORM和进行测试吗?关于这个主题,因为我的具体数据访问类dbcontext在数据层中,所以接口定义是否应该进入域/业务层,这意味着如果数据访问技术发生了变化,我的其他层是否会受到影响?

根据到目前为止的研究,我的结构如下所示:

MVC Internet应用程序 ->标准Internet项目-这里的模型是ViewModels

域/业务层 ->特定于业务的类/模型,控制器可以使用这些类/模型来处理数据层中的域实体,然后再传递到相关视图

存储库抽象有必要吗?->我听到很多关于此的辩论,尤其是在使用ORM时

数据层 ->实体类(汽车,货车,摩托车),DbContext-具体数据访问技术层

Answers:


26

您的问题涉及很多概念,涉及很多概念,但是当我想到中大型MVC应用程序时,这是我的基本建议:

演示<--->业务逻辑<---->数据访问

首先,最好不要将应用程序视为“ MVC应用程序”。这是一个使用MVC模式作为其表示组件的应用程序。以这种方式进行思考将帮助您将业务逻辑问题与表示问题分开。小型应用程序可以将所有内容集中到数据库访问MVC结构中,这也许是可以的,但是对于中大型应用程序来说,它将很快变得站不住脚。

MVC(演示)

在您的应用中,ASP.NET MVC组件应处理用于显示目的的业务数据转换(模型),显示用户界面(视图)以及通讯问题,例如路由,身份验证,授权,请求验证,响应处理以及像(控制器)。如果您有执行其他操作的代码,则它不属于MVC组件

储存库/ ORM(数据访问)

同样在您的应用程序中,数据访问层应与检索和存储持久性数据有关。通常,这是关系数据库的形式,但是还有许多其他可以持久化数据的方式。如果您的代码没有读取或存储持久性数据,那么它就不属于数据层。我之前在SO 分享了对ORM /存储库讨论的想法,但总而言之,出于多种原因,我认为ORM与存储库不一样。

商业逻辑

因此,现在您有了表示层(MVC)和数据层(存储库或ORM)...其他所有内容都是业务逻辑层(BLL)。决定要检索哪些数据,执行复杂计算或做出业务决策的所有代码都应在此处。我通常以“服务”的形式组织我的业务逻辑,我的表示层可以调用它来完成请求的工作。我所有的域模型都在这里。

您的方法

这是您的方法对我有所帮助的地方。您将MVC控制器描述为将从存储库中获取数据的位置,然后调用MPGCalculator进行一些工作,等等。我不会让我的控制器来执行任何操作,而是将所有这些操作委托给服务在BLL中。

换句话说,我不会将存储库和MPGCalculator注入到控制器中,这会给控制器带来太多责任(它已经处理了我上面提到的所有控制器内容)。相反,我将在BLL中拥有一个服务来处理所有这些服务,并将结果传递回控制器。然后,控制器可以将结果转换为正确的模型,并将其传递给正确的视图。控制器中没有任何业务逻辑,并且注入控制器的唯一内容是适当的BLL服务。

这样做意味着您的业务逻辑(例如,给定一组车辆,计算MPG并按最佳至最差的顺序进行排序)与表示和持久性关注无关。通常它将位于不知道或不在乎数据持久性策略或表示策略的库中。


嗨,埃里克(Eric),非常好的答复-关于存储库,我认为具体的类将存在于数据访问层以及业务/服务层的“ ICarRepository”等中?然后,我可以将服务注入到我的控制器中,该控制器根据要求可以包含1个或多个存储库?
迈克尔·哈珀

@MichaelHarper是的,这听起来像是一种完美的解决方法。
埃里克·金

1
虽然身份验证是控制器的考虑因素(不同的UI身份验证方式不同),但我要说授权是业务逻辑,并且属于业务层。你同意吗?
汤姆(Tom)2014年

1
@tom是的,你有一个好点。我一直在思考简单的授权,因为用户可以访问此路由,但是可以做的事情不止于此。“更多的东西”部分属于业务层。
埃里克·金

1
@HunterNelson如果要映射到视图模型,则映射应在表示层的视图所在位置进行。在其他任何地方都没有意义。
埃里克·金

0

看起来一切都适合您的结构。我唯一不确定的是,您提到MVC中的模型是“ ViewModels”,并且您的控制器与域层通信。我认为,如果您的默认模式是使用控制器访问域层,然后将“ ViewModels”用作来自多个域实体的信息的更多特定于视图的汇编,则这有意义,因为该特定视图是有意义的。如果那是您在做什么,那您可能还可以。

有一种流派认为,如果要使用MVC应用程序,则应该对域层进行完整的抽象。就个人而言,在企业应用程序中执行此操作的想法使我严重的精神痛苦。

我更喜欢使用存储库模式来管理对数据层的访问,因为它增强了可测试性和灵活性。界面和数据库是最容易发生巨大变化的两件事。想象一下,如果您要直接从数据库中拉出的某些信息已更改,因此必须从服务调用而不是数据库调用中进行检索,或者某些信息已移至需要不同.edmx的其他数据库中文件。存储库模式提供了抽象来支持这一点。


感谢您的答复威廉😊我会考虑我的业务对象/逻辑和域实体“模型”该控制器用来处理用户动作和作为的ViewModels可能含有的车型组视具体型号等
迈克尔·哈珀
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.