使用存储库时,ASP.NET MVC 中业务逻辑的最佳位置是啥?

Posted

技术标签:

【中文标题】使用存储库时,ASP.NET MVC 中业务逻辑的最佳位置是啥?【英文标题】:What is the best place for business logic in ASP.NET MVC when using repositories?使用存储库时,ASP.NET MVC 中业务逻辑的最佳位置是什么? 【发布时间】:2011-12-08 07:57:15 【问题描述】:

在 ASP.NET MVC 项目中为数据库实现 Repository 时,将业务逻辑放入其中是否正确,或者将逻辑放入控制器类中是否更好?或者使用额外的服务和帮助类来操作数据?

【问题讨论】:

【参考方案1】:

除了它自己的层(作为“模型”层的一部分)之外,您的业务逻辑最终没有一个完美的地方。通常您可以采用不同的实现方式,但在每种情况下都需要权衡取舍。

为业务逻辑创建另一个层的权衡是您必须实际封装您的代码。如果您过于激进,您的实体和域模型之间可能还会出现一些重复(如果您的数据库的关系语义已经处理了您的业务逻辑)。

查看

视图是应用中最脆弱的部分,因为它最有可能发生变化。

由于必须支持所有各种视图状态转换,因此在您的视图中获得正确的业务逻辑也非常困难。

众所周知,现在你只是不这样做 :)

存储库

这里的问题是抽象的维护和纯度之一。违反此规定会使人们感到困惑并使您的应用难以维护。

来自the P of EAA article on the Repository pattern:

存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样

存储库是一种抽象,它将您的数据存储呈现为一个集合,包含域对象。

没有域逻辑应该驻留在其中。相反,它应该存在于您的域对象中(根据定义,因为您的业务逻辑您的域)。

否则(让您的存储库执行双重职责并验证域逻辑)将违反 SRP (Single Responsibility Principle),并且会产生代码异味。

您可以让更高级别的域对象与域对象的集合一起工作以验证域逻辑(例如对象集合中的依赖关系、大小限制等)。他们仍将在幕后使用您的存储库来进行域对象的最终存储/检索,因此他们不会承担双重职责(因此不会违反 SRP)。

控制器

控制器也不是放置业务逻辑的好地方。控制器的工作是在控制器和模型之间进行调解。

模型就是领域,领域就是你的业务逻辑。

实体

您可以考虑将域数据放入实体中。

但是,如果附加了实体,则在访问导航属性时必须小心,因为您可能会触发无意的数据库查询或异常(取决于您的上下文是否已释放)。分离它们也是一个问题,因为它会破坏您的对象图,除非您在将对象从上下文中分离后明确地将它们重新附加到彼此。

如果您创建单独的域模型类,您可能会考虑仅将实体视为DTOs。

编辑:IValidatableObject

我刚刚发现了 Entity Framework 4.1 中的一个功能,您可能想了解一下:IValidatableObject 接口。

您可以使您的实体成为分部类,并在分部类中实现此接口。当您这样做时,Entity Framework 将在保存时调用 Validate,并且您可以在需要时调用 Validate

这可能有助于避免在其他情况下将持久性模型与域模型分开。

见这篇文章:http://msdn.microsoft.com/en-us/data/gg193959

旁注:视图/视图模型

如果您正在考虑它,我建议您避免将实体传递回视图的诱惑。它会在很多情况下中断(例如 javascript 序列化以存储视图状态),并在其他情况下导致无意的 DB 查询。而是传回简单类型(字符串、整数、列表、哈希集、字典等),或者构造视图模型类以传递给视图。

【讨论】:

感谢您的出色回答!一个问题:如果我们将业务逻辑放在模型类中,我们是否应该将模型视为 ViewModel(类似于 WPF 中的东西)? @Alexander:有一些相似之处,是的。但是我不确定当您看到术语视图模型时您会想到哪些事情。视图和域模型对象之间的一对一关系并不像视图和视图模型对象之间那样普遍。与视图模型(通常只是单个 WPF 应用程序,尽管可能是该应用程序的多个部分)相比,设计域模型以适应多个应用程序的需求(例如,在整个 Web GUI 和 Web 服务中使用)更为常见. @Alexander:查看我刚刚对IValidatableObject 界面所做的编辑(靠近底部)。它不会完全解决任何这些问题,但会帮助您避免在某些情况下将域模型与持久性模型分开。【参考方案2】:

添加一个Service Layer,将模型传递给Repository,其中可以添加控制器对应的Service类。例如,如果您使用 UserController 和 User Model,您可以将 User Model 传递给 UserService 类。

在这里,Service Layer 可以充当 Repository 和控制器之间的桥梁,从而很好地建立了 Controller 和 Repository 的分离。

【讨论】:

【参考方案3】:

业务逻辑应该存在于您的域模型中。

请查看此答案。

ASP.NET MVC - Should business logic exist in controllers?

【讨论】:

+1;在我发布答案后阅读此内容。更简洁,虽然同一点:)【参考方案4】:

我同意上述观点,控制器不应该仅仅为返回适当的视图而负责业务逻辑。我使用服务层来提供业务逻辑和视图模型创建,以便控制器简单地将服务返回的模型传递给视图。

我还确保我的视图模型是简单的 DTO,并且服务只知道如何适当地填充属性。

【讨论】:

【参考方案5】:

在我看来,这取决于业务逻辑。是否基于输入和输入规则验证的逻辑,如果是这样,最好放在模型上。但是,如果它是基于工作流的业务规则,那么可能需要在控制器中,例如,用户选择选项 A 然后被重定向到与选择选项 B 不同的页面/表单。如果业务规则必须处理数据持久性,那么它可能需要进入存储库(将它放在那里对我来说似乎很奇怪)。对此进行了大量讨论,但这取决于您或您的团队对最终产品的可维护性和灵活性的看法。

【讨论】:

以上是关于使用存储库时,ASP.NET MVC 中业务逻辑的最佳位置是啥?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 2 在哪里放置逻辑

ASP.NET MVC

ASP.NET MVC:BLL 和 DAL 到存储库设计

ASP.NET MVC – 模型简介

ASP.NET开发实战——ASP.NET MVC & 分层 代码篇

asp.net中的三层架构是啥意思