1

我一直在努力通过在我的Web应用程序中实现IoC的细节,但是以利用Microsoft.Practices.ServiceLocation的方式。我特别使用Autofac和asp.net集成,但我想让自己开放给其他容器。沿着this question的路线,我很担心如何访问我的Web应用程序代码中的容器。Autofac,ASP.NET和Microsoft.Practices.ServiceLocation

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

由于每个请求的容器可能不同,因此在Web环境中很棘手,而在非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()提供的内容。

我向专家提出的问题是,这是否有意义?我有一个简单的方法可以找到可以解决依赖关系的问题,而无需知道容器产品是什么或容器本身来自哪里。你怎么看?

回答

2

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

当所有依赖关系都可以被注入并且您的代码不再依赖于服务定位符时,IoC的真正好处就可以实现。 Autofac.Integration.Web有处理程序将执行注入您的页面对象,这将使静态服务定位器过时。伊莫这是首选的方式,但(在我们的情况下)服务定位不能总是避免。

也就是说,既然您已经使用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>(); 
    } 
} 
+0

这是非常酷的彼得,但我希望能够重用我的“核心”库在其他情况下,甚至没有基于网络。不过,我认为这是一个很好的答案,因为它有助于我避免太多的抽象。谢谢! – n8wrl 2009-10-08 13:51:34

+0

我明白你的观点。尽管如此,如果你完全可以不使用服务定位器模式,而只使用依赖注入,你根本不需要解决这个问题:) – 2009-10-08 15:18:24