Autofac,ASP.NET和Microsoft.Practices.ServiceLocation

时间:2009-09-03 18:31:02

标签: asp.net dependency-injection ioc-container autofac service-locator

我一直在通过我的网络应用程序实现IoC的细节工作,但是以一种利用Microsoft.Practices.ServiceLocation的方式。我专门使用Autofac和asp.net集成,但我想让自己对其他容器开放。在this question的方面,我担心如何在我的网络应用程序代码中访问容器。

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

在网络环境中这很棘手,因为每个请求的容器可能不同,而在非Web应用程序中,它可能始终是相同的。起初我尝试使用方法注入容器direclty,但是在下一个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()提供的内容。

我向专家提出的问题是,这有意义吗?我有一个简单的方法来获得可以解决依赖关系的东西,而不知道容器产品是什么或容器本身来自何处。你觉得怎么样?

1 个答案:

答案 0 :(得分:2)

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

当可以注入所有依赖项并且您的代码不再依赖于服务定位器时,实现了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>();
    }
}