如何在没有全局静态服务(非服务定位器解决方案)的情况下实现IOC?

Mic*_*hel 30 c# ioc-container inversion-of-control unity-container

我们想使用Unity for IOC.我所看到的是有一个全局静态服务(我们称之为IOCService)的实现,它包含对Unity容器的引用,该容器注册所有接口/类组合,每个类都询问该对象:给我一个实现为Ithis或IThat.

我经常看到这种模式不好的响应,因为它导致从ALL类到IOCService的依赖(而不是Unity容器,因为它只在IOCService内部知道).

但我经常看不到的是:替代方式是什么?

米歇尔

编辑:发现全局静态服务被称为服务定位器,将其添加到标题中.

Jef*_*nal 11

另一种方法是仅在最高应用程序级别拥有容器的单个实例,然后使用该容器来解析需要在该层中创建的每个对象实例.

例如,大多数可执行文件的主要方法看起来像这样(减去异常处理):

private static void main(string[] args) {

     Container container = new Container();

     // Configure the container - by hand or via file

     IProgramLogic logic = container.Resolve<IProgramLogic>();

     logic.Run();
}
Run Code Online (Sandbox Code Playgroud)

你的程序(在这里由IProgramLogic实例表示)不需要知道你的容器,因为container.Resolve它将创建它的所有依赖项 - 及其依赖项的依赖项,而不是它们自己的依赖项.


ASP.NET是一个更难的案例,因为Web表单不支持构造函数注入.我通常在我的Web表单应用程序中使用Model-View-Presenter,因此我的Page类实际上只有一个依赖项 - 在他们的演示者上.我不单元测试他们(一切有趣和可测试的是在我的演讲,这是我做的测试),并且我从来没有替代主持人.所以我不打击框架 - 我只是在我的HttpApplication类(在global.asax.cs中)公开一个容器属性,并直接从我的Page文件中使用它:

protected void Page_Load(object sender, EventArgs args) {
    ICustomerPresenter presenter = Global.Container.Resolve<ICustomerPresenter>();
    presenter.Load();
}
Run Code Online (Sandbox Code Playgroud)

那当然是服务定位器 - 虽然Page类是唯一与定位器耦合的东西:您的演示者及其所有依赖项仍然与您的IoC容器实现完全分离.

如果你的文件中有很多依赖项Page(也就是说,如果你不使用Model-View-Presenter),或者你的Page类与Global应用程序类分离很重要,你应该尝试找到一个集成的框架进入Web表单请求管道并使用属性注入(如Nicholas在下面的评论中所建议的) - 或者自己编写并自己IHttpModule执行属性注入.

  • 这仍然是经常被建议的相同模式(服务定位器).即使在ASP.NET WebForms中,也可以通过属性注入(http://code.google.com/p/autofac/wiki/AspNetIntegration#Implementing_WebForms_Pages_and_User_Controls)或通过重构到演示者驱动的方法来实现依赖注入. (2认同)

Krz*_*mic 7

知道服务定位器是坏事的 +1 .

问题是 - Unity不是很复杂,所以我不知道用它做正确的IoC是多么容易/多难.

我最近写了几篇博文,你可能会发现它很有用.


Gar*_*ian 5

而不是显式使用容器,而是通过利用构造函数/属性注入隐式使用它.创建依赖于应用程序所有主要部分的核心类(或核心类集).

大多数容器都会让你ISomething[]输入构造函数,它会将所有实例注入ISomething到你的类中.

这样,当您引导应用程序时:

  1. 实例化您的容器
  2. 注册所有好吃的东西
  3. 解析核心类(这将引入您需要的所有其他依赖项)
  4. 运行应用程序的"主要"部分

现在,根据您编写的应用程序类型,有不同的策略可以避免将IoC容器标记为"静态".

对于ASP.NET Web应用程序,您可能最终将容器存储在Application State中.对于ASP.NET MVC应用程序,您需要更改Controller Factory.

对于桌面应用程序,事情变得更加复杂. Caliburn使用IResult构造对此问题使用了一个有趣的解决方案(这适用于WPF应用程序,但也可以适用于Windows窗体.