我一直在通过我的网络应用程序实现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()提供的内容。
我向专家提出的问题是,这有意义吗?我有一个简单的方法来获得可以解决依赖关系的东西,而不知道容器产品是什么或容器本身来自何处。你觉得怎么样?
答案 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>();
}
}