Asp.net mvc 3 为什么Unity使用服务定位器?

Asp.net mvc 3 为什么Unity使用服务定位器?,asp.net-mvc-3,unity-container,service-locator,Asp.net Mvc 3,Unity Container,Service Locator,我在asp.net mvc3中使用Unity的几个教程中看到了这一行代码。我的印象是服务定位器是一种反模式,而不是最佳实践。这个服务定位器是不是定义了反模式之外的东西,或者这行代码/这个实现被认为是错误的做法 ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container)); 这正是人们所说的反彭定康。该行所做的只是将服务定位器提供程序设置为UnityServiceLocator的实例,即使用ISeri

我在asp.net mvc3中使用Unity的几个教程中看到了这一行代码。我的印象是服务定位器是一种反模式,而不是最佳实践。这个服务定位器是不是定义了反模式之外的东西,或者这行代码/这个实现被认为是错误的做法

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container));

这正是人们所说的反彭定康。该行所做的只是将服务定位器提供程序设置为UnityServiceLocator的实例,即使用ISerivceLocator的Unity实现。或者,如果您愿意,您可以使用自己的实现IServiceLocator,并使用它代替UnityServiceLocator


使用服务定位器被认为是一种不好的做法,原因如下所列

如果您创建了一个设计为容器无关的框架,那么服务定位器(尽管它在应用程序中应该是禁止的)是一个额外的间接层,允许您将Unity换成不同的东西。此外,服务定位器的使用并不强制使用DI用于使用该框架的应用程序。

老问题,但为了其他人的利益:

虽然我完全同意“服务地点是一种反模式”的说法,但这条规则肯定有例外

当您使用依赖注入(比如Unity)时,是的,当然不要使用ServiceLocator,而只对所有服务类使用构造函数注入。(除DTO等值对象外,不要将“new”用于任何其他对象。)

但是,在某些情况下,您无法使用构造函数注入,而访问服务的唯一方法是使用变通方法直接访问Unity容器,在这种情况下,ServiceLocator是实现这一点的一种很好的标准方法。例如,当类不是由您实例化(或者更具体地说,它不是由Unity实例化)而是由.NET framework实例化时,就是这种情况

ServiceLocator可能有用的几个简单示例是从以下位置访问Unity容器中注册的服务:

  • WCF IEndpointBehavior或IClientMessageInspector的实现
  • WPF-IValueConverter的一种实现
  • 或者,您可能甚至不想从类中访问“服务”,但您只想编写可单元测试的代码,但由于某些原因,该类根本无法稳定(或不容易稳定),因为它通常由.NET Framework构建,因此您将自定义代码提取到可测试的类中,并使用ServiceLocator在不可测试类中解析它
  • 请注意,这一行并不理想:

    ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container));
    
    ServiceLocator.Current属性将在每次访问Current时执行提供的委托,即每次都将创建一个新的UnityServiceLocator。相反,您可能希望这样做:

    IServiceLocator locator = new UnityServiceLocator(container);
    ServiceLocator.SetLocatorProvider(() => locator);
    

    我也见过很多这样的应用,在Prism StockTrader RI中,他们也将ServiceLocator与MEF一起使用。我还认为这是一种反模式,因此在RI中看到它时感到惊讶。我相信这与定义的反模式是相同的服务定位器模式实现。您的理解是相反的:在您的示例中,使用服务定位器的不是Unity,而是您的代码插件通过服务定位器与asp.net mvc3的Unity。关于服务定位模式的争论具有宗教性质。net mvc团队必须提供一种方法来使用您最喜欢的DI容器,这就是他们实现它的方式。考虑其他选择。这里有一些关于@zespri问题的更深入的见解-因此并非所有Unity实现都使用服务定位器?我只知道一个Unity实现。它不使用服务定位器。如果您愿意(即使Unity没有明确支持),您可以使用它作为服务定位器,但它确实支持这种情况。@zespri-我非常希望避免使用服务定位器,你知道有没有关于asp.net mvc3的教程显示了没有服务定位器的简单unity设置?我同意服务定位器是一种不好的做法,我只是不确定这是否只是名义上的使用。如果你使用的是IOC容器,你如何找到容器?它有它的位置,请参阅其他答案,它使您的代码不必直接绑定到特定的DI实现。@philsoady我认为桌面应用程序的答案是向任何需要容器的类添加一个类型为IUnityContainer的构造函数参数(请参阅)。对于其他应用程序类型,可能无法做到这一点,因此需要使用服务定位器。我个人认为,如果没有其他选择,仅使用它来获取DI容器是可以接受的。