为什么MVC4使用服务定位器反模式?

47

阅读了Mark Seemann的《.NET中的依赖注入》之后,我远离了反模式服务定位器

阅读了MVC 4版本发布说明后,我看到:

通过DependencyResolver改进了控制反转(IoC): Web API现在使用MVC的依赖解析器实现的服务定位器模式来获取许多不同设施的实例。

因此我很好奇并困惑为什么微软会在2012年使用服务定位器。

2个回答

51

这是一个实现细节,您不需要关心。重要的是,现在Web API使用DependencyResolver解决许多不同设施的依赖关系,您可以随时使用真正的依赖注入来插入这些设施。因此,在您的代码中,您将使用真正的依赖注入。如果Microsoft没有使用DependencyResolver ,那么你就必须在你的代码中使用它(作为服务定位器反模式),以便在想要实现一些自定义功能时解决依赖问题。这对于你来说会很糟糕。现在对于Microsoft来说很糟糕,但您不需要关心他们。

因此,我很好奇和困惑为什么Microsoft在2012年会使用服务定位器。

因为设计框架与使用框架设计应用程序是不同的。在设计可重复使用的框架(例如ASP.NET MVC)时,需要考虑一些不同的因素,而不仅仅是书上所写的内容。一些例子是设计框架的方式,使使用该框架的人能够在使用该框架的代码中采用书上写的最佳实践。


9
+1 框架和应用程序遵循不同的规则。您希望框架是容器无关的(以防想要使用该框架的应用程序已经使用了不同的容器),并且通常不会强制应用程序使用 DI(因为它们可能根本不想使用 DI)。 - Sebastian Weber
23
我不相信只因为它是框架,服务定位器就是合适的。是的,框架和应用程序不同,但完全可以编写一个不使用服务定位器的框架。看看ASP.NET MVC 1和2,甚至像WCF这样复杂的东西。问题在于ASP.NET MVC 3+中的DependencyResolver不仅是内部实现细节,而且被公开宣传为公共“依赖注入支持”。 - Mark Seemann
4
以下是一些指南:https://dev59.com/QnI-5IYBdhLWcg3wBjrl#2047657 - Mark Seemann
11
“糟糕的开发者”问题目前没有解决方案。但这并不会以任何方式否定我的观点。服务定位器也无法解决这个问题......” - Mark Seemann
5
@MarkSeemann,如果您将此作为答案发布,那就太好了。看起来OP正在寻找更多的答案。 - Darin Dimitrov
显示剩余5条评论

35

正如Darin所指出的,ASP.NET MVC 4是一个框架,它不依赖于容器。这就是为什么它提供了IDependencyResolver形式的服务定位器。这使任何人都可以插入他们选择的容器。

然而,我不认为这是一种反模式。这允许您使用所选的容器,但它并不强制应用程序开发人员使用服务定位。如果框架强制开发人员使用服务定位,则我会称其为反模式。但构建ASP.NET MVC应用程序的开发人员可以通过构造函数注入、属性设置或服务定位来自由使用DI。这是他们的选择。

看看我或ASP.NET MVC团队发布的所有依赖注入的ASP.NET MVC示例。在几乎所有情况下,它们都使用构造函数注入。它们不使用服务定位。

实际上,大多数ASP.NET MVC源代码本身并不使用服务定位来检索依赖项。有一些关键位置,MVC会调用服务定位器来处理一些遗留API之类的事情。但仅此而已。


3
听起来很合理,但我仍然想知道为什么马尔钦·多波什(http://blogs.msdn.com/b/marcinon/)在给我发电子邮件时提到马克的书和服务定位器是反模式。他说:“我没有看过这本书,所以不熟悉它为什么是反模式的论据。你能澄清一下为什么你认为它是一个糟糕的设计吗?” - Tom Stickel
3
为了澄清,我给在微软工作的Marcin发了一封电子邮件,惊讶地发现他从未听说过服务定位器被称为反模式(这在互联网上很容易找到)。我并不是要指责他,但我认为这是Mark S.所指的例子。 - Tom Stickel
你说:“看看我或者ASP.NET MVC团队发布的所有依赖注入示例。” 你能提供一些你建议的链接吗?我有一些服务引用,许多控制器使用它们。它们获取一个对象,该对象由模型对象(构造函数或方法)提供,以形成一个模型(如果您愿意,可以称之为viewModel),然后提供给View。我想要进行IoC的主要原因是从我的测试项目中,我希望能够提供另一个实现IService的东西,而不必从我的测试项目中调用Service。 - David Hollowell - MSFT
我明白为什么需要支持遗留代码和在简单情况下避免过度依赖注入。我只是想知道为什么他们没有使用 System.IServiceProvider 而要创建一个新的接口,然后为每个真正的依赖注入容器编写新的包装类? - Chris Woodward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接