1

我一直在研究在我的 Web 应用程序中实现 IoC 的细节,但以一种利用 Microsoft.Practices.ServiceLocation 的方式。我专门使用 Autofac 和 asp.net 集成,但我想让自己对其他容器开放。按照这个问题,我担心如何在我的网络应用程序代码中访问容器。

我有一个“核心”库,主要定义要解析的接口。我的网络应用程序和其他应用程序也使用这个核心库。定义通用接口非常方便。我认为这是一个访问 IoC 容器的好地方,我使用静态类做到了这一点。诀窍是将容器注入静态类。

在 Web 环境中这很棘手,因为每个请求的容器可能不同,而在非 Web 应用程序中,它可能一直都是相同的。起初我尝试使用一种方法直接注入容器,但在下一个 Web 请求中很快就失败了!所以我想出了这个:

public static class IoCContainer
{
    public static void SetServiceLocator(Func<IServiceLocator> getLocator)
    {
        m_GetLocator = getLocator;
    }
    static private Func<IServiceLocator> m_GetLocator = null;

    public static T GetInstance<T>(string typeName)
    {
        return m_GetLocator().GetInstance<T>(typeName);
    }
}

现在在我的 global.asax.cs 我这样做:

protected void Application_Start(object sender, EventArgs e)
{
    var builder = new Autofac.Builder.ContainerBuilder();
    ... register stuff ...
    var container = builder.Build();
    _containerProvider = new Autofac.Integration.Web.ContainerProvider(container);
    Xyz.Core.IoCContainer.SetServiceLocator(() => 
        new AutofacContrib.CommonServiceLocator.AutofacServiceLocator
            (_containerProvider.RequestContainer));
}
public IContainerProvider ContainerProvider
{
    get { return _containerProvider; }
}
static IContainerProvider _containerProvider;

解决依赖的呼吁看起来像

var someService = Xyz.Core.GetInstance<ISomeService>();

因此,我没有传递一个特定的容器,而是传递一个知道如何获取容器的委托。对于非 Web 应用程序,委托可能只会返回 builder.Build() 提供的内容。

我对专家的问题是,这有意义吗?我有一种简单的方法可以解决依赖关系,而无需知道容器产品是什么或容器本身来自何处。你怎么看?

4

1 回答 1

2

我们使用类似的模式主要是因为 IoC 被引入到非 DI 架构中。因此需要能够显式调用容器来获取服务,这基本上就是工厂模式。

当可以注入所有依赖项并且您的代码不再依赖于服务定位器时,IoC 的真正好处就实现了。Autofac.Integration.Web 具有将执行注入到您的页面对象的处理程序,这将使静态服务定位器过时。Imo 这是首选方式,尽管(在我们的例子中也是如此)服务定位器不能总是避免。

也就是说,由于您已经使用 IoCContainer 类将您的应用程序与容器隔离,我认为没有理由在 IoCContainer 中使用 AutofacServiceLocator 的额外抽象。底线是 IoCContainer 已经是您的服务定位器,应该“允许”直接访问容器实现。

这是我对您的服务定位器类的看法:

public static class IoCContainer
{
    private static IContext GetContainer()
    {
        var cpa = 
             (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
        return cpa.ContainerProvider.RequestContainer;
    }

    public static T GetInstance<T>()
    {
        return GetContainer().Resolve<T>();
    }
}
于 2009-10-08T08:55:16.020 回答